about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs19
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs80
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs20
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs2
-rw-r--r--src/test/ui/async-await/dyn-star-trait-error.rs12
-rw-r--r--src/test/ui/async-await/dyn-star-trait-error.stderr9
-rw-r--r--src/test/ui/dyn-star/make-dyn-star.rs14
-rw-r--r--src/test/ui/dyn-star/syntax.rs3
11 files changed, 148 insertions, 29 deletions
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 702c2d27187..6713660ab8f 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -31,7 +31,7 @@ use ty::util::IntTypeExt;
 
 use rustc_type_ir::sty::TyKind::*;
 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
 #[rustc_diagnostic_item = "TyKind"]
@@ -692,6 +692,9 @@ impl<'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> {
         use crate::ty::ToPredicate;
         match self.skip_binder() {
@@ -1849,7 +1852,12 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     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]
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index f31dde044f9..43ee5b55455 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -20,8 +20,8 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-    TraitObjectRepresentation,
+    self, EarlyBinder, TraitObjectRepresentation, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitor,
 };
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 8b15e10ba9c..a64179c14f5 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -38,6 +38,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 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::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
 use rustc_span::symbol::sym;
@@ -1865,6 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Array(..)
             | ty::Closure(..)
             | ty::Never
+            | ty::Dynamic(_, _, TraitObjectRepresentation::Sized)
             | ty::Error(_) => {
                 // safe for everything
                 Where(ty::Binder::dummy(Vec::new()))
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 586ede3d90c..0010bcc4bf6 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -28,10 +28,10 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
+use rustc_middle::ty::TraitObjectRepresentation;
 use rustc_middle::ty::{
     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_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -1253,6 +1253,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         trait_bounds: &[hir::PolyTraitRef<'_>],
         lifetime: &hir::Lifetime,
         borrowed: bool,
+        representation: TraitObjectRepresentation,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
 
@@ -1573,11 +1574,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         };
         debug!("region_bound: {:?}", region_bound);
 
-        let ty = tcx.mk_dynamic(
-            existential_predicates,
-            region_bound,
-            TraitObjectRepresentation::Unsized, // FIXME: check whether the source syntax was dyn or dyn*
-        );
+        let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation);
         debug!("trait_object_type: {:?}", ty);
         ty
     }
@@ -2623,9 +2620,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     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.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)) => {
                 debug!(?maybe_qself, ?path);
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index a3fcda5864b..fa6224f1915 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -35,12 +35,15 @@ use crate::type_error_struct;
 use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
+use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 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::Session;
 use rustc_span::symbol::sym;
@@ -52,9 +55,12 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 /// a function context.
 #[derive(Debug)]
 pub struct CastCheck<'tcx> {
+    /// The expression whose value is being casted
     expr: &'tcx hir::Expr<'tcx>,
+    /// The source type for the cast expression
     expr_ty: Ty<'tcx>,
     expr_span: Span,
+    /// The target type. That is, the type we are casting to.
     cast_ty: Ty<'tcx>,
     cast_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> {
-    pub fn new(
+    fn new(
         fcx: &FnCtxt<'a, 'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
@@ -215,7 +289,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         // cases now. We do a more thorough check at the end, once
         // inference is more completely known.
         match cast_ty.kind() {
-            ty::Dynamic(..) | ty::Slice(..) => {
+            ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Slice(..) => {
                 let reported = check.report_cast_to_unsized_type(fcx);
                 Err(reported)
             }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 21392001364..93b00850069 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -3,18 +3,15 @@
 //! See `mod.rs` for more context on type checking in general.
 
 use crate::astconv::AstConv as _;
-use crate::check::cast;
+use crate::check::cast::{self, CastCheckResult};
 use crate::check::coercion::CoerceMany;
 use crate::check::fatally_break_rust;
 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::FnCtxt;
-use crate::check::Needs;
-use crate::check::TupleArgumentsFlag::DontTupleArguments;
+use crate::check::{
+    report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
+    TupleArgumentsFlag::DontTupleArguments,
+};
 use crate::errors::{
     FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
     YieldExprOutsideOfGenerator,
@@ -1252,8 +1249,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else {
             // Defer other checks until we're done type checking.
             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) {
-                Ok(cast_check) => {
+            match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
+                CastCheckResult::Ok => t_cast,
+                CastCheckResult::Deferred(cast_check) => {
                     debug!(
                         "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
                         t_cast, t_expr, cast_check,
@@ -1261,7 +1259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
-                Err(_) => self.tcx.ty_error(),
+                CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
             }
         }
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 2bfee9a5364..82b7101baa3 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     })
                 }
-                ty::Dynamic(data, _) => {
+                ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => {
                     data.iter().find_map(|pred| {
                         if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
                         && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
diff --git a/src/test/ui/async-await/dyn-star-trait-error.rs b/src/test/ui/async-await/dyn-star-trait-error.rs
new file mode 100644
index 00000000000..20e183c7455
--- /dev/null
+++ b/src/test/ui/async-await/dyn-star-trait-error.rs
@@ -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() {}
diff --git a/src/test/ui/async-await/dyn-star-trait-error.stderr b/src/test/ui/async-await/dyn-star-trait-error.stderr
new file mode 100644
index 00000000000..932bc50ffde
--- /dev/null
+++ b/src/test/ui/async-await/dyn-star-trait-error.stderr
@@ -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`.
diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs
new file mode 100644
index 00000000000..17356bfbd84
--- /dev/null
+++ b/src/test/ui/dyn-star/make-dyn-star.rs
@@ -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() {}
diff --git a/src/test/ui/dyn-star/syntax.rs b/src/test/ui/dyn-star/syntax.rs
index dd96bf0672d..7848996e5e0 100644
--- a/src/test/ui/dyn-star/syntax.rs
+++ b/src/test/ui/dyn-star/syntax.rs
@@ -2,10 +2,9 @@
 //
 // check-pass
 
-
 #![feature(dyn_star)]
 
-pub fn dyn_star_parameter(_: &dyn* Send) {
+pub fn dyn_star_parameter(_: dyn* Send) {
 }
 
 fn main() {}