use either::Either;
+use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::vec_map::VecMap;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
+use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::{
- self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
- ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
+ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
+ OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::type_op;
+use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
+use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use rustc_trait_selection::traits::query::Fallible;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
+use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
use rustc_const_eval::transform::{
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
$context.last_span,
&format!(
"broken MIR in {:?} ({:?}): {}",
- $context.body.source.def_id(),
+ $context.body().source.def_id(),
$elem,
format_args!($($message)*),
),
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
upvars: &[Upvar<'tcx>],
+ use_polonius: bool,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut universe_causes = FxHashMap::default();
&mut borrowck_context,
|mut cx| {
cx.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
- liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
+ liveness::generate(
+ &mut cx,
+ body,
+ elements,
+ flow_inits,
+ move_data,
+ location_table,
+ use_polonius,
+ );
translate_outlives_facts(&mut cx);
- let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
+ let opaque_type_values =
+ infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
opaque_type_values
.into_iter()
- .filter_map(|(opaque_type_key, mut decl)| {
- decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
+ .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,
- decl.concrete_ty.kind()
+ hidden_type.ty.kind()
);
- if decl.concrete_ty.has_infer_types_or_consts() {
+ if hidden_type.has_infer_types_or_consts() {
infcx.tcx.sess.delay_span_bug(
- body.span,
- &format!("could not resolve {:#?}", decl.concrete_ty.kind()),
+ decl.hidden_type.span,
+ &format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
- decl.concrete_ty = infcx.tcx.ty_error();
+ hidden_type.ty = infcx.tcx.ty_error();
}
- let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
- {
- *def_id == opaque_type_key.def_id
- } else {
- false
- };
- if concrete_is_opaque {
- // We're using an opaque `impl Trait` type without
- // 'revealing' it. For example, code like this:
- //
- // type Foo = impl Debug;
- // fn foo1() -> Foo { ... }
- // fn foo2() -> Foo { foo1() }
- //
- // In `foo2`, we're not revealing the type of `Foo` - we're
- // just treating it as the opaque type.
- //
- // When this occurs, we do *not* want to try to equate
- // the concrete type with the underlying defining type
- // of the opaque type - this will always fail, since
- // the defining type of an opaque type is always
- // some other type (e.g. not itself)
- // Essentially, none of the normal obligations apply here -
- // we're just passing around some unknown opaque type,
- // without actually looking at the underlying type it
- // gets 'revealed' into
- debug!(
- "eq_opaque_type_and_type: non-defining use of {:?}",
- opaque_type_key.def_id,
- );
- None
- } else {
- Some((opaque_type_key, decl))
- }
+ (opaque_type_key, (hidden_type, decl.origin))
})
.collect()
},
borrowck_context,
);
let errors_reported = {
- let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
+ let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
verifier.errors_reported
};
/// is a problem.
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
- body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
last_span: Span,
errors_reported: bool,
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location);
- let rval_ty = rvalue.ty(self.body, self.tcx());
+ let rval_ty = rvalue.ty(self.body(), self.tcx());
self.sanitize_type(rvalue, rval_ty);
}
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
fn new(
cx: &'a mut TypeChecker<'b, 'tcx>,
- body: &'b Body<'tcx>,
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
) -> Self {
- TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
+ TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
+ }
+
+ fn body(&self) -> &Body<'tcx> {
+ self.cx.body
}
fn tcx(&self) -> TyCtxt<'tcx> {
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
- let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
+ let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
for elem in place.projection.iter() {
if place_ty.variant_index.is_none() {
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
- let parent_body = mem::replace(&mut self.body, promoted_body);
+ let parent_body = mem::replace(&mut self.cx.body, promoted_body);
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
self.cx.typeck_mir(promoted_body);
}
- self.body = parent_body;
+ self.cx.body = parent_body;
// Merge the outlives constraints back in, at the given location.
swap_constraints(self);
}))
}
ProjectionElem::Index(i) => {
- let index_ty = Place::from(i).ty(self.body, tcx).ty;
+ let index_ty = Place::from(i).ty(self.body(), tcx).ty;
if index_ty != tcx.types.usize {
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
} else {
}
ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind() {
ty::Adt(adt_def, _substs) if adt_def.is_enum() => {
- if index.as_usize() >= adt_def.variants.len() {
+ if index.as_usize() >= adt_def.variants().len() {
PlaceTy::from_ty(span_mirbug_and_err!(
self,
place,
"cast to variant #{:?} but enum only has {:?}",
index,
- adt_def.variants.len()
+ adt_def.variants().len()
))
} else {
PlaceTy { ty: base_ty, variant_index: Some(index) }
let (variant, substs) = match base_ty {
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
- ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs),
+ ty::Adt(adt_def, substs) => (adt_def.variant(variant_index), substs),
ty::Generator(def_id, substs, _) => {
let mut variants = substs.as_generator().state_tys(def_id, tcx);
- let mut variant = match variants.nth(variant_index.into()) {
- Some(v) => v,
- None => bug!(
+ let Some(mut variant) = variants.nth(variant_index.into()) else {
+ bug!(
"variant_index of generator out of range: {:?}/{:?}",
variant_index,
substs.as_generator().state_tys(def_id, tcx).count()
- ),
+ );
};
return match variant.nth(field.index()) {
Some(ty) => Ok(ty),
},
PlaceTy { ty, variant_index: None } => match *ty.kind() {
ty::Adt(adt_def, substs) if !adt_def.is_enum() => {
- (&adt_def.variants[VariantIdx::new(0)], substs)
+ (adt_def.variant(VariantIdx::new(0)), substs)
}
ty::Closure(_, substs) => {
return match substs
.as_closure()
.tupled_upvars_ty()
- .tuple_element_ty(field.index())
+ .tuple_fields()
+ .get(field.index())
{
- Some(ty) => Ok(ty),
+ Some(&ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
field_count: substs.as_closure().upvar_tys().count(),
}),
}
ty::Tuple(tys) => {
return match tys.get(field.index()) {
- Some(&ty) => Ok(ty.expect_ty()),
+ Some(&ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }),
};
}
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
- crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
+ crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
}
/// A collection of region constraints that must be satisfied for the
checker
}
+ fn body(&self) -> &Body<'tcx> {
+ self.body
+ }
+
fn unsized_feature_enabled(&self) -> bool {
let features = self.tcx().features();
features.unsized_locals || features.unsized_fn_params
}
/// Equate the inferred type and the annotated type for user type annotations
+ #[instrument(skip(self), level = "debug")]
fn check_user_type_annotations(&mut self) {
- debug!(
- "check_user_type_annotations: user_type_annotations={:?}",
- self.user_type_annotations
- );
+ debug!(?self.user_type_annotations);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
tcx,
self.param_env,
proj,
- |this, field, &()| {
+ |this, field, ()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
Ok(())
}
- /// Equates a type `anon_ty` that may contain opaque types whose
- /// values are to be inferred by the MIR.
- ///
- /// The type `revealed_ty` contains the same type as `anon_ty`, but with the
- /// hidden types for impl traits revealed.
- ///
- /// # Example
- ///
- /// Consider a piece of code like
- ///
- /// ```rust
- /// type Foo<U> = impl Debug;
- ///
- /// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
- /// Box::new((t, 22_u32))
- /// }
- /// ```
- ///
- /// Here, the function signature would be something like
- /// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
- /// the type with the opaque type revealed, so `Box<(T, u32)>`.
- ///
- /// In terms of our function parameters:
- ///
- /// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
- /// scoped to this function (note that it is parameterized by the
- /// generics of `foo`). Note that `anon_ty` is not just the opaque type,
- /// but the entire return type (which may contain opaque types within it).
- /// * `revealed_ty` would be `Box<(T, u32)>`
- #[instrument(skip(self), level = "debug")]
- fn eq_opaque_type_and_type(
- &mut self,
- revealed_ty: Ty<'tcx>,
- anon_ty: Ty<'tcx>,
- locations: Locations,
- category: ConstraintCategory,
- ) -> Fallible<()> {
- // Fast path for the common case.
- if !anon_ty.has_opaque_types() {
- if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
- span_mirbug!(
- self,
- locations,
- "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
- revealed_ty,
- anon_ty,
- terr
- );
- }
- return Ok(());
- }
-
- let param_env = self.param_env;
- let body = self.body;
- let mir_def_id = body.source.def_id().expect_local();
-
- debug!(?mir_def_id);
- self.fully_perform_op(
- locations,
- category,
- CustomTypeOp::new(
- |infcx| {
- let mut obligations = ObligationAccumulator::default();
-
- let dummy_body_id = hir::CRATE_HIR_ID;
-
- // Replace the opaque types defined by this function with
- // inference variables, creating a map. In our example above,
- // this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
- // to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
- // (Note that the key of the map is both the def-id of `Foo` along with
- // any generic parameters.)
- let output_ty = obligations.add(infcx.instantiate_opaque_types(
- dummy_body_id,
- param_env,
- anon_ty,
- locations.span(body),
- ));
- debug!(?output_ty, ?revealed_ty);
-
- // Make sure that the inferred types are well-formed. I'm
- // not entirely sure this is needed (the HIR type check
- // didn't do this) but it seems sensible to prevent opaque
- // types hiding ill-formed types.
- obligations.obligations.push(traits::Obligation::new(
- ObligationCause::dummy(),
- param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
- .to_predicate(infcx.tcx),
- ));
- obligations.add(
- infcx
- .at(&ObligationCause::dummy(), param_env)
- .eq(output_ty, revealed_ty)?,
- );
-
- debug!("equated");
-
- Ok(InferOk { value: (), obligations: obligations.into_vec() })
- },
- || "input_output".to_string(),
- ),
- )?;
-
- // Finally, if we instantiated the anon types successfully, we
- // have to solve any bounds (e.g., `-> impl Iterator` needs to
- // prove that `T: Iterator` where `T` is the type we
- // instantiated it with).
- let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
- for (opaque_type_key, opaque_decl) in opaque_type_map {
- self.fully_perform_op(
- locations,
- ConstraintCategory::OpaqueType,
- CustomTypeOp::new(
- |infcx| {
- infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
- Ok(InferOk { value: (), obligations: vec![] })
- },
- || "opaque_type_map".to_string(),
- ),
- )?;
- }
- Ok(())
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
);
}
};
- if variant_index.as_usize() >= adt.variants.len() {
+ if variant_index.as_usize() >= adt.variants().len() {
span_bug!(
stmt.source_info.span,
"bad set discriminant ({:?} = {:?}): value of of range",
match *ak {
AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => {
let def = tcx.adt_def(adt_did);
- let variant = &def.variants[variant_index];
+ let variant = &def.variant(variant_index);
let adj_field_index = active_field_index.unwrap_or(field_index);
if let Some(field) = variant.fields.get(adj_field_index) {
Ok(self.normalize(field.ty(tcx, substs), location))
ObligationCause::new(
span,
self.tcx().hir().local_def_id_to_hir_id(def_id),
- traits::ObligationCauseCode::RepeatVec(is_const_fn),
+ traits::ObligationCauseCode::RepeatElementCopy {
+ is_const_fn,
+ },
),
self.param_env,
ty::Binder::dummy(ty::TraitRef::new(
}
CastKind::Pointer(PointerCast::MutToConstPointer) => {
- let ty_from = match op.ty(body, tcx).kind() {
- ty::RawPtr(ty::TypeAndMut {
- ty: ty_from,
- mutbl: hir::Mutability::Mut,
- }) => ty_from,
- _ => {
- span_mirbug!(
- self,
- rvalue,
- "unexpected base type for cast {:?}",
- ty,
- );
- return;
- }
+ let ty::RawPtr(ty::TypeAndMut {
+ ty: ty_from,
+ mutbl: hir::Mutability::Mut,
+ }) = op.ty(body, tcx).kind() else {
+ span_mirbug!(
+ self,
+ rvalue,
+ "unexpected base type for cast {:?}",
+ ty,
+ );
+ return;
};
- let ty_to = match ty.kind() {
- ty::RawPtr(ty::TypeAndMut {
- ty: ty_to,
- mutbl: hir::Mutability::Not,
- }) => ty_to,
- _ => {
- span_mirbug!(
- self,
- rvalue,
- "unexpected target type for cast {:?}",
- ty,
- );
- return;
- }
+ let ty::RawPtr(ty::TypeAndMut {
+ ty: ty_to,
+ mutbl: hir::Mutability::Not,
+ }) = ty.kind() else {
+ span_mirbug!(
+ self,
+ rvalue,
+ "unexpected target type for cast {:?}",
+ ty,
+ );
+ return;
};
if let Err(terr) = self.sub_types(
*ty_from,
_ => None,
};
- let (ty_elem, ty_mut) = match opt_ty_elem_mut {
- Some(ty_elem_mut) => ty_elem_mut,
- None => {
- span_mirbug!(
- self,
- rvalue,
- "ArrayToPointer cast from unexpected type {:?}",
- ty_from,
- );
- return;
- }
+ let Some((ty_elem, ty_mut)) = opt_ty_elem_mut else {
+ span_mirbug!(
+ self,
+ rvalue,
+ "ArrayToPointer cast from unexpected type {:?}",
+ ty_from,
+ );
+ return;
};
let (ty_to, ty_to_mut) = match ty.kind() {
// we have to solve them here where we instantiate the
// closure.
//
- // Despite the opacity of the previous parapgrah, this is
+ // Despite the opacity of the previous paragraph, this is
// actually relatively easy to understand in terms of the
// desugaring. A closure gets desugared to a struct, and
// these extra requirements are basically like where
}
}
-#[derive(Debug, Default)]
-struct ObligationAccumulator<'tcx> {
- obligations: PredicateObligations<'tcx>,
+/// Runs `infcx.instantiate_opaque_types`. Unlike other `TypeOp`s,
+/// this is not canonicalized - it directly affects the main `InferCtxt`
+/// that we use during MIR borrowchecking.
+#[derive(Debug)]
+pub(super) struct InstantiateOpaqueType<'tcx> {
+ pub base_universe: Option<ty::UniverseIndex>,
+ pub region_constraints: Option<RegionConstraintData<'tcx>>,
+ pub obligations: Vec<PredicateObligation<'tcx>>,
}
-impl<'tcx> ObligationAccumulator<'tcx> {
- fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
- let InferOk { value, obligations } = value;
- self.obligations.extend(obligations);
- value
- }
-
- fn into_vec(self) -> PredicateObligations<'tcx> {
- self.obligations
+impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
+ type Output = ();
+ /// We use this type itself to store the information used
+ /// when reporting errors. Since this is not a query, we don't
+ /// re-run anything during error reporting - we just use the information
+ /// we saved to help extract an error from the already-existing region
+ /// constraints in our `InferCtxt`
+ type ErrorInfo = InstantiateOpaqueType<'tcx>;
+
+ fn fully_perform(mut self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ let (mut output, region_constraints) = scrape_region_constraints(infcx, || {
+ Ok(InferOk { value: (), obligations: self.obligations.clone() })
+ })?;
+ self.region_constraints = Some(region_constraints);
+ output.error_info = Some(self);
+ Ok(output)
}
}