Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle opaques in the new solver (take 2?) #111473

Merged
merged 8 commits into from
May 25, 2023
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) {
Copy link
Contributor

@lcnr lcnr May 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is that fine (for TAIT)? 🤔 aren't the preregistered opaque types in the wrong environment now, they have the generic params of the opaque while in the context of the defining scope?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a thought which also deals with rust-lang/trait-system-refactor-initiative#17

long term we could maybe end up with the following to replace DefiningAnchor:

enum DefineOpaques {
    // the current `DefiningAnchor::Bind`
    Yes(&'tcx List<DefId>),
    // We do not allow any new definitions for our opaques,
    // but when using an opaque with `DefId`, we instantiate the
    // inferred hidden type with these substs.
    //
    // This doesn't quite work because of lifetimes, but we can
    // figure something out there :grin:
    No(SomeMapCollection<DefId, EarlyBinder<Ty<'tcx>>),
}

anyways, your PR works for RPIT so I wouldn't mind us landing this as long as we put a fixme here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right lol. We shouldn't map RPITITs back to their declaration params during writeback if we're in the new trait solver. 🤦

I'll add a fixme anyways.

// 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