diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_borrowck/src/type_check/mod.rs | 223 |
1 files changed, 118 insertions, 105 deletions
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() { |