Typecheck dyn* coercions
Also changes things to treat dyn* as a sized type, unlike dyn Trait.
This commit is contained in:
parent
6c01273a15
commit
7fccac3ea0
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::sty::TyKind::*;
|
||||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||||
use rustc_type_ir::TyKind as IrTyKind;
|
use rustc_type_ir::{TraitObjectRepresentation, TyKind as IrTyKind};
|
||||||
|
|
||||||
// Re-export the `TyKind` from `rustc_type_ir` here for convenience
|
// Re-export the `TyKind` from `rustc_type_ir` here for convenience
|
||||||
#[rustc_diagnostic_item = "TyKind"]
|
#[rustc_diagnostic_item = "TyKind"]
|
||||||
@ -692,6 +692,9 @@ pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> {
|
impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> {
|
||||||
|
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||||
|
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
||||||
|
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
|
||||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
|
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
|
||||||
use crate::ty::ToPredicate;
|
use crate::ty::ToPredicate;
|
||||||
match self.skip_binder() {
|
match self.skip_binder() {
|
||||||
@ -1849,7 +1852,12 @@ pub fn is_floating_point(self) -> bool {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_trait(self) -> bool {
|
pub fn is_trait(self) -> bool {
|
||||||
matches!(self.kind(), Dynamic(..))
|
matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Unsized))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_dyn_star(self) -> bool {
|
||||||
|
matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Sized))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
|
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
|
||||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
|
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
self, EarlyBinder, TraitObjectRepresentation, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||||
TraitObjectRepresentation,
|
TypeVisitor,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{Predicate, ToPredicate};
|
use rustc_middle::ty::{Predicate, ToPredicate};
|
||||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::relate::TypeRelation;
|
use rustc_middle::ty::relate::TypeRelation;
|
||||||
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||||
|
use rustc_middle::ty::TraitObjectRepresentation;
|
||||||
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
|
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -1865,6 +1866,7 @@ fn sized_conditions(
|
|||||||
| ty::Array(..)
|
| ty::Array(..)
|
||||||
| ty::Closure(..)
|
| ty::Closure(..)
|
||||||
| ty::Never
|
| ty::Never
|
||||||
|
| ty::Dynamic(_, _, TraitObjectRepresentation::Sized)
|
||||||
| ty::Error(_) => {
|
| ty::Error(_) => {
|
||||||
// safe for everything
|
// safe for everything
|
||||||
Where(ty::Binder::dummy(Vec::new()))
|
Where(ty::Binder::dummy(Vec::new()))
|
||||||
|
@ -28,10 +28,10 @@
|
|||||||
use rustc_middle::middle::stability::AllowUnstable;
|
use rustc_middle::middle::stability::AllowUnstable;
|
||||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
|
use rustc_middle::ty::TraitObjectRepresentation;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
|
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{TraitObjectRepresentation};
|
|
||||||
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
@ -1253,6 +1253,7 @@ fn conv_object_ty_poly_trait_ref(
|
|||||||
trait_bounds: &[hir::PolyTraitRef<'_>],
|
trait_bounds: &[hir::PolyTraitRef<'_>],
|
||||||
lifetime: &hir::Lifetime,
|
lifetime: &hir::Lifetime,
|
||||||
borrowed: bool,
|
borrowed: bool,
|
||||||
|
representation: TraitObjectRepresentation,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
@ -1573,11 +1574,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
|
|||||||
};
|
};
|
||||||
debug!("region_bound: {:?}", region_bound);
|
debug!("region_bound: {:?}", region_bound);
|
||||||
|
|
||||||
let ty = tcx.mk_dynamic(
|
let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation);
|
||||||
existential_predicates,
|
|
||||||
region_bound,
|
|
||||||
TraitObjectRepresentation::Unsized, // FIXME: check whether the source syntax was dyn or dyn*
|
|
||||||
);
|
|
||||||
debug!("trait_object_type: {:?}", ty);
|
debug!("trait_object_type: {:?}", ty);
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
@ -2623,9 +2620,15 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
|
|||||||
Some(ast_ty),
|
Some(ast_ty),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
|
hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
|
||||||
self.maybe_lint_bare_trait(ast_ty, in_path);
|
self.maybe_lint_bare_trait(ast_ty, in_path);
|
||||||
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
|
let repr = match repr {
|
||||||
|
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => {
|
||||||
|
TraitObjectRepresentation::Unsized
|
||||||
|
}
|
||||||
|
TraitObjectSyntax::DynStar => TraitObjectRepresentation::Sized,
|
||||||
|
};
|
||||||
|
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
|
||||||
}
|
}
|
||||||
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
|
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
|
||||||
debug!(?maybe_qself, ?path);
|
debug!(?maybe_qself, ?path);
|
||||||
|
@ -35,12 +35,15 @@
|
|||||||
use hir::def_id::LOCAL_CRATE;
|
use hir::def_id::LOCAL_CRATE;
|
||||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
|
||||||
use rustc_middle::mir::Mutability;
|
use rustc_middle::mir::Mutability;
|
||||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||||
use rustc_middle::ty::cast::{CastKind, CastTy};
|
use rustc_middle::ty::cast::{CastKind, CastTy};
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
|
use rustc_middle::ty::{
|
||||||
|
self, Binder, TraitObjectRepresentation, Ty, TypeAndMut, TypeVisitable, VariantDef,
|
||||||
|
};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -52,9 +55,12 @@
|
|||||||
/// a function context.
|
/// a function context.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CastCheck<'tcx> {
|
pub struct CastCheck<'tcx> {
|
||||||
|
/// The expression whose value is being casted
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
/// The source type for the cast expression
|
||||||
expr_ty: Ty<'tcx>,
|
expr_ty: Ty<'tcx>,
|
||||||
expr_span: Span,
|
expr_span: Span,
|
||||||
|
/// The target type. That is, the type we are casting to.
|
||||||
cast_ty: Ty<'tcx>,
|
cast_ty: Ty<'tcx>,
|
||||||
cast_span: Span,
|
cast_span: Span,
|
||||||
span: Span,
|
span: Span,
|
||||||
@ -199,8 +205,76 @@ fn make_invalid_casting_error<'a, 'tcx>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum CastCheckResult<'tcx> {
|
||||||
|
Ok,
|
||||||
|
Deferred(CastCheck<'tcx>),
|
||||||
|
Err(ErrorGuaranteed),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_cast<'tcx>(
|
||||||
|
fcx: &FnCtxt<'_, 'tcx>,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
expr_ty: Ty<'tcx>,
|
||||||
|
cast_ty: Ty<'tcx>,
|
||||||
|
cast_span: Span,
|
||||||
|
span: Span,
|
||||||
|
) -> CastCheckResult<'tcx> {
|
||||||
|
if cast_ty.is_dyn_star() {
|
||||||
|
check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
|
||||||
|
} else {
|
||||||
|
match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
|
||||||
|
Ok(check) => CastCheckResult::Deferred(check),
|
||||||
|
Err(e) => CastCheckResult::Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_dyn_star_cast<'tcx>(
|
||||||
|
fcx: &FnCtxt<'_, 'tcx>,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
expr_ty: Ty<'tcx>,
|
||||||
|
cast_ty: Ty<'tcx>,
|
||||||
|
) -> CastCheckResult<'tcx> {
|
||||||
|
// Find the bounds in the dyn*. For eaxmple, if we have
|
||||||
|
//
|
||||||
|
// let x = 22_usize as dyn* (Clone + Debug + 'static)
|
||||||
|
//
|
||||||
|
// this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
|
||||||
|
let (existential_predicates, region) = match cast_ty.kind() {
|
||||||
|
ty::Dynamic(predicates, region, TraitObjectRepresentation::Sized) => (predicates, region),
|
||||||
|
_ => panic!("Invalid dyn* cast_ty"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let cause = ObligationCause::new(
|
||||||
|
expr.span,
|
||||||
|
fcx.body_id,
|
||||||
|
// FIXME: Use a better obligation cause code
|
||||||
|
ObligationCauseCode::MiscObligation,
|
||||||
|
);
|
||||||
|
|
||||||
|
// For each existential predicate (e.g., `?Self: Clone`) substitute
|
||||||
|
// the type of the expression (e.g., `usize` in our example above)
|
||||||
|
// and then require that the resulting predicate (e.g., `usize: Clone`)
|
||||||
|
// holds (it does).
|
||||||
|
for existential_predicate in existential_predicates.iter() {
|
||||||
|
let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
|
||||||
|
fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
|
||||||
|
fcx.register_predicate(Obligation::new(
|
||||||
|
cause,
|
||||||
|
fcx.param_env,
|
||||||
|
fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
|
||||||
|
ty::OutlivesPredicate(expr_ty, *region),
|
||||||
|
))),
|
||||||
|
));
|
||||||
|
|
||||||
|
CastCheckResult::Ok
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> CastCheck<'tcx> {
|
impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
pub fn new(
|
fn new(
|
||||||
fcx: &FnCtxt<'a, 'tcx>,
|
fcx: &FnCtxt<'a, 'tcx>,
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
expr_ty: Ty<'tcx>,
|
expr_ty: Ty<'tcx>,
|
||||||
@ -215,7 +289,7 @@ pub fn new(
|
|||||||
// cases now. We do a more thorough check at the end, once
|
// cases now. We do a more thorough check at the end, once
|
||||||
// inference is more completely known.
|
// inference is more completely known.
|
||||||
match cast_ty.kind() {
|
match cast_ty.kind() {
|
||||||
ty::Dynamic(..) | ty::Slice(..) => {
|
ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Slice(..) => {
|
||||||
let reported = check.report_cast_to_unsized_type(fcx);
|
let reported = check.report_cast_to_unsized_type(fcx);
|
||||||
Err(reported)
|
Err(reported)
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,15 @@
|
|||||||
//! See `mod.rs` for more context on type checking in general.
|
//! See `mod.rs` for more context on type checking in general.
|
||||||
|
|
||||||
use crate::astconv::AstConv as _;
|
use crate::astconv::AstConv as _;
|
||||||
use crate::check::cast;
|
use crate::check::cast::{self, CastCheckResult};
|
||||||
use crate::check::coercion::CoerceMany;
|
use crate::check::coercion::CoerceMany;
|
||||||
use crate::check::fatally_break_rust;
|
use crate::check::fatally_break_rust;
|
||||||
use crate::check::method::SelfSource;
|
use crate::check::method::SelfSource;
|
||||||
use crate::check::report_unexpected_variant_res;
|
|
||||||
use crate::check::BreakableCtxt;
|
|
||||||
use crate::check::Diverges;
|
|
||||||
use crate::check::DynamicCoerceMany;
|
|
||||||
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||||
use crate::check::FnCtxt;
|
use crate::check::{
|
||||||
use crate::check::Needs;
|
report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
|
||||||
use crate::check::TupleArgumentsFlag::DontTupleArguments;
|
TupleArgumentsFlag::DontTupleArguments,
|
||||||
|
};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
|
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
|
||||||
YieldExprOutsideOfGenerator,
|
YieldExprOutsideOfGenerator,
|
||||||
@ -1252,8 +1249,9 @@ fn check_expr_cast(
|
|||||||
} else {
|
} else {
|
||||||
// Defer other checks until we're done type checking.
|
// Defer other checks until we're done type checking.
|
||||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||||
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
|
match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
|
||||||
Ok(cast_check) => {
|
CastCheckResult::Ok => t_cast,
|
||||||
|
CastCheckResult::Deferred(cast_check) => {
|
||||||
debug!(
|
debug!(
|
||||||
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
|
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
|
||||||
t_cast, t_expr, cast_check,
|
t_cast, t_expr, cast_check,
|
||||||
@ -1261,7 +1259,7 @@ fn check_expr_cast(
|
|||||||
deferred_cast_checks.push(cast_check);
|
deferred_cast_checks.push(cast_check);
|
||||||
t_cast
|
t_cast
|
||||||
}
|
}
|
||||||
Err(_) => self.tcx.ty_error(),
|
CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ pub(in super::super) fn extract_callable_info(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::Dynamic(data, _) => {
|
ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => {
|
||||||
data.iter().find_map(|pred| {
|
data.iter().find_map(|pred| {
|
||||||
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
||||||
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
|
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
|
||||||
|
12
src/test/ui/async-await/dyn-star-trait-error.rs
Normal file
12
src/test/ui/async-await/dyn-star-trait-error.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#![feature(async_fn_in_traits)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
trait Foo {}
|
||||||
|
|
||||||
|
fn make_dyn_star() {
|
||||||
|
let i = 42;
|
||||||
|
let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/async-await/dyn-star-trait-error.stderr
Normal file
9
src/test/ui/async-await/dyn-star-trait-error.stderr
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
error[E0277]: the trait bound `{integer}: Foo` is not satisfied
|
||||||
|
--> $DIR/dyn-star-trait-error.rs:9:27
|
||||||
|
|
|
||||||
|
LL | let dyn_i: dyn* Foo = i as dyn* Foo;
|
||||||
|
| ^ the trait `Foo` is not implemented for `{integer}`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
14
src/test/ui/dyn-star/make-dyn-star.rs
Normal file
14
src/test/ui/dyn-star/make-dyn-star.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// check-pass
|
||||||
|
#![feature(dyn_star)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
pub fn dyn_star_parameter(_: dyn* Send) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_dyn_star() {
|
||||||
|
let i = 42usize;
|
||||||
|
let dyn_i: dyn* Debug = i as dyn* Debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -2,10 +2,9 @@
|
|||||||
//
|
//
|
||||||
// check-pass
|
// check-pass
|
||||||
|
|
||||||
|
|
||||||
#![feature(dyn_star)]
|
#![feature(dyn_star)]
|
||||||
|
|
||||||
pub fn dyn_star_parameter(_: &dyn* Send) {
|
pub fn dyn_star_parameter(_: dyn* Send) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
Loading…
Reference in New Issue
Block a user