diff options
Diffstat (limited to 'compiler/rustc_borrowck/src/type_check')
4 files changed, 218 insertions, 173 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 6cfe5efb6..9271a2f4d 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -24,8 +24,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// **Any `rustc_infer::infer` operations that might generate region /// constraints should occur within this method so that those /// constraints can be properly localized!** - #[instrument(skip(self, category, op), level = "trace")] - pub(super) fn fully_perform_op<R, Op>( + #[instrument(skip(self, op), level = "trace")] + pub(super) fn fully_perform_op<R: fmt::Debug, Op>( &mut self, locations: Locations, category: ConstraintCategory<'tcx>, @@ -39,6 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?; + debug!(?output, ?constraints); + if let Some(data) = constraints { self.push_region_constraints(locations, category, data); } @@ -90,17 +92,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) { - self.prove_predicates( - Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { + self.prove_predicate( + ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: ty::BoundConstness::NotConst, polarity: ty::ImplPolarity::Positive, - }))), + })) + .to_predicate(self.tcx()), locations, category, ); } + #[instrument(level = "debug", skip(self))] pub(super) fn normalize_and_prove_instantiated_predicates( &mut self, // Keep this parameter for now, in case we start using @@ -115,8 +119,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .zip(instantiated_predicates.spans.into_iter()) { debug!(?predicate); - let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); + let category = ConstraintCategory::Predicate(span); + let predicate = self.normalize_with_category(predicate, locations, category); + self.prove_predicate(predicate, locations, category); } } @@ -152,15 +157,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }) } - #[instrument(skip(self), level = "debug")] pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { + self.normalize_with_category(value, location, ConstraintCategory::Boring) + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn normalize_with_category<T>( + &mut self, + value: T, + location: impl NormalizeLocation, + category: ConstraintCategory<'tcx>, + ) -> T + where + T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, + { let param_env = self.param_env; self.fully_perform_op( location.to_locations(), - ConstraintCategory::Boring, + category, param_env.and(type_op::normalize::Normalize::new(value)), ) .unwrap_or_else(|NoSolution| { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 167960918..71eae0583 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Span, DUMMY_SP}; @@ -86,7 +86,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { + fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) { debug!("generate: constraints at: {:#?}", self.locations); // Extract out various useful fields we'll need below. @@ -98,34 +98,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // region constraints like `for<'a> 'a: 'b`. At some point // when we move to universes, we will, and this assertion // will start to fail. - let ty::OutlivesPredicate(k1, r2) = query_constraint.no_bound_vars().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound vars", query_constraint,); - }); + let ty::OutlivesPredicate(k1, r2) = + query_constraint.0.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", query_constraint,); + }); + + let constraint_category = query_constraint.1; match k1.unpack() { GenericArgKind::Lifetime(r1) => { let r1_vid = self.to_region_vid(r1); let r2_vid = self.to_region_vid(r2); - self.add_outlives(r1_vid, r2_vid); + self.add_outlives(r1_vid, r2_vid, constraint_category); } - GenericArgKind::Type(mut t1) => { + GenericArgKind::Type(t1) => { // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. let origin = infer::RelateParamBound(DUMMY_SP, t1, None); - // Placeholder regions need to be converted now because it may - // create new region variables, which can't be done later when - // verifying these bounds. - if t1.has_placeholders() { - t1 = tcx.fold_regions(t1, |r, _| match *r { - ty::RePlaceholder(placeholder) => { - self.constraints.placeholder_region(self.infcx, placeholder) - } - _ => r, - }); - } - TypeOutlives::new( &mut *self, tcx, @@ -133,7 +124,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { Some(implicit_region_bound), param_env, ) - .type_must_outlive(origin, t1, r2); + .type_must_outlive(origin, t1, r2, constraint_category); } GenericArgKind::Const(_) => { @@ -143,6 +134,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } + /// Placeholder regions need to be converted eagerly because it may + /// create new region variables, which we must not do when verifying + /// our region bounds. + /// + /// FIXME: This should get removed once higher ranked region obligations + /// are dealt with during trait solving. + fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { + if value.has_placeholders() { + self.tcx.fold_regions(value, |r, _| match *r { + ty::RePlaceholder(placeholder) => { + self.constraints.placeholder_region(self.infcx, placeholder) + } + _ => r, + }) + } else { + value + } + } + fn verify_to_type_test( &mut self, generic_kind: GenericKind<'tcx>, @@ -150,7 +160,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { verify_bound: VerifyBound<'tcx>, ) -> TypeTest<'tcx> { let lower_bound = self.to_region_vid(region); - TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound } } @@ -162,10 +171,19 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) { + fn add_outlives( + &mut self, + sup: ty::RegionVid, + sub: ty::RegionVid, + category: ConstraintCategory<'tcx>, + ) { + let category = match self.category { + ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category, + _ => self.category, + }; self.constraints.outlives_constraints.push(OutlivesConstraint { locations: self.locations, - category: self.category, + category, span: self.span, sub, sup, @@ -185,10 +203,11 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' _origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + constraint_category: ConstraintCategory<'tcx>, ) { let b = self.to_region_vid(b); let a = self.to_region_vid(a); - self.add_outlives(b, a); + self.add_outlives(b, a, constraint_category); } fn push_verify( @@ -198,6 +217,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, bound: VerifyBound<'tcx>, ) { + let kind = self.replace_placeholders_with_nll(kind); + let bound = self.replace_placeholders_with_nll(bound); let type_test = self.verify_to_type_test(kind, a, bound); self.add_type_test(type_test); } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index cc0318ede..f1b1c33a1 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -1,5 +1,5 @@ use rustc_data_structures::frozen::Frozen; -use rustc_data_structures::transitive_relation::TransitiveRelation; +use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -61,25 +61,13 @@ pub(crate) fn create<'tcx>( constraints, universal_regions: universal_regions.clone(), region_bound_pairs: Default::default(), - relations: UniversalRegionRelations { - universal_regions: universal_regions.clone(), - outlives: Default::default(), - inverse_outlives: Default::default(), - }, + outlives: Default::default(), + inverse_outlives: Default::default(), } .create() } impl UniversalRegionRelations<'_> { - /// Records in the `outlives_relation` (and - /// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the - /// builder below. - fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { - debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); - self.outlives.add(fr_a, fr_b); - self.inverse_outlives.add(fr_b, fr_a); - } - /// Given two universal regions, returns the postdominating /// upper-bound (effectively the least upper bound). /// @@ -216,11 +204,20 @@ struct UniversalRegionRelationsBuilder<'this, 'tcx> { constraints: &'this mut MirTypeckRegionConstraints<'tcx>, // outputs: - relations: UniversalRegionRelations<'tcx>, + outlives: TransitiveRelationBuilder<RegionVid>, + inverse_outlives: TransitiveRelationBuilder<RegionVid>, region_bound_pairs: RegionBoundPairs<'tcx>, } impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { + /// Records in the `outlives_relation` (and + /// `inverse_outlives_relation`) that `fr_a: fr_b`. + fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) { + debug!("relate_universal_regions: fr_a={:?} outlives fr_b={:?}", fr_a, fr_b); + self.outlives.add(fr_a, fr_b); + self.inverse_outlives.add(fr_b, fr_a); + } + pub(crate) fn create(mut self) -> CreateResult<'tcx> { let unnormalized_input_output_tys = self .universal_regions @@ -242,10 +239,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let constraint_sets: Vec<_> = unnormalized_input_output_tys .flat_map(|ty| { debug!("build: input_or_output={:?}", ty); - // We only add implied bounds for the normalized type as the unnormalized - // type may not actually get checked by the caller. - // - // Can otherwise be unsound, see #91068. + // We add implied bounds from both the unnormalized and normalized ty. + // See issue #87748 + let constraints_implied1 = self.add_implied_bounds(ty); let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) @@ -269,13 +265,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // } // impl Foo for () { // type Bar = (); - // fn foo(&self) ->&() {} + // fn foo(&self) -> &() {} // } // ``` // Both &Self::Bar and &() are WF - let constraints_implied = self.add_implied_bounds(norm_ty); + let constraints_implied2 = + if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; normalized_inputs_and_output.push(norm_ty); - constraints1.into_iter().chain(constraints_implied) + constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2) }) .collect(); @@ -292,9 +289,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let fr_fn_body = self.universal_regions.fr_fn_body; for fr in self.universal_regions.universal_regions() { debug!("build: relating free region {:?} to itself and to 'static", fr); - self.relations.relate_universal_regions(fr, fr); - self.relations.relate_universal_regions(fr_static, fr); - self.relations.relate_universal_regions(fr, fr_fn_body); + self.relate_universal_regions(fr, fr); + self.relate_universal_regions(fr_static, fr); + self.relate_universal_regions(fr, fr_fn_body); } for data in &constraint_sets { @@ -313,7 +310,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } CreateResult { - universal_region_relations: Frozen::freeze(self.relations), + universal_region_relations: Frozen::freeze(UniversalRegionRelations { + universal_regions: self.universal_regions, + outlives: self.outlives.freeze(), + inverse_outlives: self.inverse_outlives.freeze(), + }), region_bound_pairs: self.region_bound_pairs, normalized_inputs_and_output, } @@ -346,17 +347,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { match outlives_bound { OutlivesBound::RegionSubRegion(r1, r2) => { - // `where Type:` is lowered to `where Type: 'empty` so that - // we check `Type` is well formed, but there's no use for - // this bound here. - if r1.is_empty() { - return; - } - // The bound says that `r1 <= r2`; we store `r2: r1`. let r1 = self.universal_regions.to_region_vid(r1); let r2 = self.universal_regions.to_region_vid(r2); - self.relations.relate_universal_regions(r2, r1); + self.relate_universal_regions(r2, r1); } OutlivesBound::RegionSubParam(r_a, param_b) => { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d32b1edcd..3713ec3f5 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, - OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, + self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, + OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, + UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -178,97 +179,15 @@ pub(crate) fn type_check<'mir, 'tcx>( upvars, }; - let opaque_type_values = type_check_internal( + let mut checker = TypeChecker::new( infcx, - param_env, body, - promoted, + param_env, ®ion_bound_pairs, implicit_region_bound, &mut borrowck_context, - |mut cx| { - debug!("inside extra closure of type_check_internal"); - cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); - liveness::generate( - &mut cx, - body, - elements, - flow_inits, - move_data, - location_table, - use_polonius, - ); - - translate_outlives_facts(&mut cx); - let opaque_type_values = - infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - - opaque_type_values - .into_iter() - .map(|(opaque_type_key, decl)| { - cx.fully_perform_op( - Locations::All(body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |infcx| { - infcx.register_member_constraints( - param_env, - opaque_type_key, - decl.hidden_type.ty, - decl.hidden_type.span, - ); - Ok(InferOk { value: (), obligations: vec![] }) - }, - || "opaque_type_map".to_string(), - ), - ) - .unwrap(); - let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); - trace!( - "finalized opaque type {:?} to {:#?}", - opaque_type_key, - hidden_type.ty.kind() - ); - if hidden_type.has_infer_types_or_consts() { - infcx.tcx.sess.delay_span_bug( - decl.hidden_type.span, - &format!("could not resolve {:#?}", hidden_type.ty.kind()), - ); - hidden_type.ty = infcx.tcx.ty_error(); - } - - (opaque_type_key, (hidden_type, decl.origin)) - }) - .collect() - }, ); - MirTypeckResults { constraints, universal_region_relations, opaque_type_values } -} - -#[instrument( - skip(infcx, body, promoted, region_bound_pairs, borrowck_context, extra), - level = "debug" -)] -fn type_check_internal<'a, 'tcx, R>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body: &'a Body<'tcx>, - promoted: &'a IndexVec<Promoted, Body<'tcx>>, - region_bound_pairs: &'a RegionBoundPairs<'tcx>, - implicit_region_bound: ty::Region<'tcx>, - borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, - extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, -) -> R { - debug!("body: {:#?}", body); - let mut checker = TypeChecker::new( - infcx, - body, - param_env, - region_bound_pairs, - implicit_region_bound, - borrowck_context, - ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, promoted); verifier.visit_body(&body); @@ -280,7 +199,56 @@ fn type_check_internal<'a, 'tcx, R>( checker.typeck_mir(body); } - extra(checker) + checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output); + liveness::generate( + &mut checker, + body, + elements, + flow_inits, + move_data, + location_table, + use_polonius, + ); + + translate_outlives_facts(&mut checker); + let opaque_type_values = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + let opaque_type_values = opaque_type_values + .into_iter() + .map(|(opaque_type_key, decl)| { + checker + .fully_perform_op( + Locations::All(body.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |infcx| { + infcx.register_member_constraints( + param_env, + opaque_type_key, + decl.hidden_type.ty, + decl.hidden_type.span, + ); + Ok(InferOk { value: (), obligations: vec![] }) + }, + || "opaque_type_map".to_string(), + ), + ) + .unwrap(); + let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); + if hidden_type.has_infer_types_or_consts() { + infcx.tcx.sess.delay_span_bug( + decl.hidden_type.span, + &format!("could not resolve {:#?}", hidden_type.ty.kind()), + ); + hidden_type.ty = infcx.tcx.ty_error(); + } + + (opaque_type_key, (hidden_type, decl.origin)) + }) + .collect(); + + MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { @@ -344,6 +312,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { + debug!(?constant, ?location, "visit_constant"); + self.super_constant(constant, location); let ty = self.sanitize_type(constant, constant.literal.ty()); @@ -387,11 +357,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { let tcx = self.tcx(); let maybe_uneval = match constant.literal { ConstantKind::Ty(ct) => match ct.kind() { - ty::ConstKind::Unevaluated(uv) => Some(uv), + ty::ConstKind::Unevaluated(_) => { + bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct) + } _ => None, }, + ConstantKind::Unevaluated(uv, _) => Some(uv), _ => None, }; + if let Some(uv) = maybe_uneval { if let Some(promoted) = uv.promoted { let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, @@ -1076,6 +1050,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let inferred_ty = self.normalize(inferred_ty, Locations::All(span)); let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); + debug!(?annotation); match annotation { UserType::Ty(mut ty) => { ty = self.normalize(ty, Locations::All(span)); @@ -1334,12 +1309,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => span_bug!( - stmt.source_info.span, - "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", - ), + StatementKind::Intrinsic(box ref kind) => match kind { + NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location), + NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( + stmt.source_info.span, + "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics", + ), + }, StatementKind::FakeRead(..) | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) @@ -1448,9 +1424,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { )) }); debug!(?sig); - let sig = self.normalize(sig, term_location); - self.check_call_dest(body, term, &sig, *destination, target, term_location); - + // IMPORTANT: We have to prove well formed for the function signature before + // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc` + // get normalized away, causing us to ignore the `'b: 'a` bound used by the function. + // + // Normalization results in a well formed type if the input is well formed, so we + // don't have to check it twice. + // + // See #91068 for an example. self.prove_predicates( sig.inputs_and_output .iter() @@ -1458,6 +1439,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { term_location.to_locations(), ConstraintCategory::Boring, ); + let sig = self.normalize(sig, term_location); + self.check_call_dest(body, term, &sig, *destination, target, term_location); // The ordinary liveness rules will ensure that all // regions in the type of the callee are live here. We @@ -1834,14 +1817,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { + debug!(?op, ?location, "check_operand"); + if let Operand::Constant(constant) = op { let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.kind() { - ty::ConstKind::Unevaluated(uv) => Some(uv), - _ => None, - }, - _ => None, + ConstantKind::Val(..) | ConstantKind::Ty(_) => None, + ConstantKind::Unevaluated(uv, _) => Some(uv), }; + if let Some(uv) = maybe_uneval { if uv.promoted.is_none() { let tcx = self.tcx(); @@ -1904,7 +1887,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(_, ty) => { + &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2033,6 +2016,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } + CastKind::DynStar => { + // get the constraints from the target type (`dyn* Clone`) + // + // apply them to prove that the source type `Foo` implements `Clone` etc + let (existential_predicates, region) = match ty.kind() { + Dynamic(predicates, region, ty::DynStar) => (predicates, region), + _ => panic!("Invalid dyn* cast_ty"), + }; + + let self_ty = op.ty(body, tcx); + + self.prove_predicates( + existential_predicates + .iter() + .map(|predicate| predicate.with_self_ty(tcx, self_ty)), + location.to_locations(), + ConstraintCategory::Cast, + ); + + let outlives_predicate = + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + ))); + self.prove_predicate( + outlives_predicate, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + CastKind::Pointer(PointerCast::MutToConstPointer) => { let ty::RawPtr(ty::TypeAndMut { ty: ty_from, @@ -2584,7 +2597,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .enumerate() .filter_map(|(idx, constraint)| { let ty::OutlivesPredicate(k1, r2) = - constraint.no_bound_vars().unwrap_or_else(|| { + constraint.0.no_bound_vars().unwrap_or_else(|| { bug!("query_constraint {:?} contained bound vars", constraint,); }); @@ -2659,7 +2672,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_local(&body, local, local_decl); } - for (block, block_data) in body.basic_blocks().iter_enumerated() { + for (block, block_data) in body.basic_blocks.iter_enumerated() { let mut location = Location { block, statement_index: 0 }; for stmt in &block_data.statements { if !stmt.source_info.span.is_dummy() { |