Skip to content

Commit

Permalink
Auto merge of rust-lang#111473 - compiler-errors:opaques, r=lcnr
Browse files Browse the repository at this point in the history
Handle opaques in the new solver (take 2?)

Implement a new strategy for handling opaques in the new solver.

First, queries now carry both their defining anchor and the opaques that were defined in the inference context at the time of canonicalization. These are both used to pre-populate the inference context used by the canonical query.

Second, use the normalizes-to goal to handle opaque types in the new solver. This means that opaques are handled like projection aliases, but with their own rules:
* Can only define opaques if they're "defining uses" (i.e. have unique params in all their substs).
* Can only define opaques that are from the anchor.
* Opaque type definitions are modulo regions. So that means `Opaque<'?0r> = HiddenTy1` and `Opaque<?'1r> = HiddenTy2` equate `HiddenTy1` and `HiddenTy2` instead of defining them as different opaque type keys.
  • Loading branch information
bors committed May 25, 2023
2 parents 0b011b7 + dd98198 commit eb9da7b
Show file tree
Hide file tree
Showing 42 changed files with 658 additions and 189 deletions.
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/consumers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

use rustc_hir::def_id::LocalDefId;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::{Body, Promoted};
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::TyCtxt;
use std::rc::Rc;

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::ChunkedBitSet;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::{
DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
};
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
Expand All @@ -36,6 +36,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc_middle::query::Providers;
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt};
use rustc_session::lint::builtin::UNUSED_MUT;
use rustc_span::{Span, Symbol};
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::InferCtxt;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
Expand Down
61 changes: 61 additions & 0 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;

use crate::renumber::RegionCtxt;
use crate::session_diagnostics::MoveUnsized;
use crate::{
borrow_set::BorrowSet,
Expand Down Expand Up @@ -183,6 +184,15 @@ pub(crate) fn type_check<'mir, 'tcx>(
&mut borrowck_context,
);

// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
// predefined opaques in the typeck root.
// FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since
// the HIR typeck map defining usages back to their definition params,
// they won't actually match up with the usages in this body...
if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
checker.register_predefined_opaques_in_new_solver();
}

let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);

Expand Down Expand Up @@ -1023,6 +1033,57 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
checker
}

pub(super) fn register_predefined_opaques_in_new_solver(&mut self) {
// OK to use the identity substitutions for each opaque type key, since
// we remap opaques from HIR typeck back to their definition params.
let opaques: Vec<_> = self
.infcx
.tcx
.typeck(self.body.source.def_id().expect_local())
.concrete_opaque_types
.iter()
.map(|(&def_id, &hidden_ty)| {
let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id);
(ty::OpaqueTypeKey { def_id, substs }, hidden_ty)
})
.collect();

let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
self.infcx.next_nll_region_var(
NllRegionVariableOrigin::Existential { from_forall: false },
|| RegionCtxt::Unknown,
)
});

let param_env = self.param_env;
let result = self.fully_perform_op(
Locations::All(self.body.span),
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|ocx| {
for (key, hidden_ty) in renumbered_opaques {
ocx.register_infer_ok_obligations(
ocx.infcx.register_hidden_type_in_new_solver(
key,
param_env,
hidden_ty.ty,
)?,
);
}
Ok(())
},
"register pre-defined opaques",
),
);

if result.is_err() {
self.infcx.tcx.sess.delay_span_bug(
self.body.span,
"failed re-defining predefined opaques in mir typeck",
);
}
}

fn body(&self) -> &Body<'tcx> {
self.body
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/util/compare_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
//! FIXME: Move this to a more general place. The utility of this extends to
//! other areas of the compiler as well.

use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::traits::{DefiningAnchor, ObligationCause};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_trait_selection::traits::ObligationCtxt;

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_typeck/src/inherited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_infer/src/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,7 @@ impl<'tcx> InferCtxt<'tcx> {
bug!()
}

(_, ty::Alias(AliasKind::Projection | AliasKind::Inherent, _))
| (ty::Alias(AliasKind::Projection | AliasKind::Inherent, _), _)
if self.tcx.trait_solver_next() =>
{
(_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => {
relation.register_type_relate_obligation(a, b);
Ok(a)
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/infer/equate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
&& def_id.is_local() =>
&& def_id.is_local()
&& !self.tcx().trait_solver_next() =>
{
self.fields.obligations.extend(
infcx
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_infer/src/infer/lattice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ where
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),

(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
if this.define_opaque_types() == DefineOpaqueTypes::Yes
&& def_id.is_local()
&& !this.tcx().trait_solver_next() =>
{
this.register_obligations(
infcx
Expand Down
13 changes: 1 addition & 12 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::select;
use rustc_middle::traits::{select, DefiningAnchor};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BoundVarReplacerDelegate;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
Expand Down Expand Up @@ -231,17 +231,6 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DefiningAnchor {
/// `DefId` of the item.
Bind(LocalDefId),
/// When opaque types are not resolved, we `Bubble` up, meaning
/// return the opaque/hidden type pair from query, for caller of query to handle it.
Bubble,
/// Used to catch type mismatch errors when handling opaque types.
Error,
}

pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,

Expand Down
22 changes: 14 additions & 8 deletions compiler/rustc_infer/src/infer/nll_relate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,16 +491,22 @@ where
(
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
self.tcx().sess.delay_span_bug(
self.delegate.span(),
"failure to relate an opaque to itself should result in an error later on",
);
if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
}),
) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => {
infcx.super_combine_tys(self, a, b).or_else(|err| {
// This behavior is only there for the old solver, the new solver
// shouldn't ever fail. Instead, it unconditionally emits an
// alias-relate goal.
assert!(!self.tcx().trait_solver_next());
self.tcx().sess.delay_span_bug(
self.delegate.span(),
"failure to relate an opaque to itself should result in an error later on",
);
if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
})
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if def_id.is_local() =>
if def_id.is_local() && !self.tcx().trait_solver_next() =>
{
self.relate_opaques(a, b)
}
Expand Down
72 changes: 59 additions & 13 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{DefineOpaqueTypes, InferResult};
use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::{self, PredicateObligation};
use hir::def_id::{DefId, LocalDefId};
use hir::OpaqueTyOrigin;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::{DefiningAnchor, ObligationCause};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::GenericArgKind;
Expand Down Expand Up @@ -48,9 +48,15 @@ impl<'tcx> InferCtxt<'tcx> {
span: Span,
param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, T> {
// We handle opaque types differently in the new solver.
if self.tcx.trait_solver_next() {
return InferOk { value, obligations: vec![] };
}

if !value.has_opaque_types() {
return InferOk { value, obligations: vec![] };
}

let mut obligations = vec![];
let replace_opaque_type = |def_id: DefId| {
def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some())
Expand Down Expand Up @@ -521,17 +527,14 @@ impl<'tcx> InferCtxt<'tcx> {
origin: hir::OpaqueTyOrigin,
a_is_expected: bool,
) -> InferResult<'tcx, ()> {
let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;

// Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`,
// these are the same span, but not in cases like `-> (impl
// Foo, impl Bar)`.
let span = cause.span;
let prev = self.inner.borrow_mut().opaque_types().register(
OpaqueTypeKey { def_id, substs },
opaque_type_key,
OpaqueHiddenType { ty: hidden_ty, span },
origin,
);
Expand All @@ -543,6 +546,49 @@ impl<'tcx> InferCtxt<'tcx> {
Vec::new()
};

self.add_item_bounds_for_hidden_type(
opaque_type_key,
cause,
param_env,
hidden_ty,
&mut obligations,
);

Ok(InferOk { value: (), obligations })
}

/// Registers an opaque's hidden type -- only should be used when the opaque
/// can be defined. For something more fallible -- checks the anchors, tries
/// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`.
pub fn register_hidden_type_in_new_solver(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
) -> InferResult<'tcx, ()> {
assert!(self.tcx.trait_solver_next());
let origin = self
.opaque_type_origin(opaque_type_key.def_id)
.expect("should be called for defining usages only");
self.register_hidden_type(
opaque_type_key,
ObligationCause::dummy(),
param_env,
hidden_ty,
origin,
true,
)
}

pub fn add_item_bounds_for_hidden_type(
&self,
OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) {
let tcx = self.tcx;
let item_bounds = tcx.explicit_item_bounds(def_id);

for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
Expand All @@ -555,14 +601,15 @@ impl<'tcx> InferCtxt<'tcx> {
// FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
ty::Alias(ty::Projection, projection_ty)
if !projection_ty.has_escaping_bound_vars()
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
&& !tcx.is_impl_trait_in_trait(projection_ty.def_id)
&& !tcx.trait_solver_next() =>
{
self.infer_projection(
param_env,
projection_ty,
cause.clone(),
0,
&mut obligations,
obligations,
)
}
// Replace all other mentions of the same opaque type with the hidden type,
Expand All @@ -588,10 +635,10 @@ impl<'tcx> InferCtxt<'tcx> {
predicate.kind().skip_binder()
{
if projection.term.references_error() {
// No point on adding these obligations since there's a type error involved.
return Ok(InferOk { value: (), obligations: vec![] });
// No point on adding any obligations since there's a type error involved.
obligations.clear();
return;
}
trace!("{:#?}", projection.term);
}
// Require that the predicate holds for the concrete type.
debug!(?predicate);
Expand All @@ -602,7 +649,6 @@ impl<'tcx> InferCtxt<'tcx> {
predicate,
));
}
Ok(InferOk { value: (), obligations })
}
}

Expand Down
Loading

0 comments on commit eb9da7b

Please sign in to comment.