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

rework opaque types for the new solver #111131

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ fn do_mir_borrowck<'tcx>(

let tcx = infcx.tcx;
let infcx = BorrowckInferCtxt::new(infcx);
let param_env = tcx.param_env(def);
let param_env = tcx.param_env_body_post_hir_typeck(def);

let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
for var_debug_info in &input_body.var_debug_info {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
));
}

let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values);
let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, param_env, opaque_type_values);

NllOutput {
regioncx,
Expand Down
129 changes: 128 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::ObligationCtxt;

Expand All @@ -17,6 +17,124 @@ use crate::session_diagnostics::NonGenericOpaqueTypeParam;
use super::RegionInferenceContext;

impl<'tcx> RegionInferenceContext<'tcx> {
/// region to pass to `infer_opaque_definition_from_instantiation`.
#[instrument(level = "debug", skip(self, infcx), ret)]
fn infer_opaque_types_next(
&self,
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();

let member_constraints: FxIndexMap<_, _> = self
.member_constraints
.all_indices()
.map(|ci| (self.member_constraints[ci].key, ci))
.collect();
debug!(?member_constraints);

for predicate in param_env.caller_bounds() {
let (opaque_ty, concrete_ty) = match predicate.kind().skip_binder() {
ty::PredicateKind::DefineOpaque(opaque_ty, concrete_ty) => {
assert!(!opaque_ty.has_escaping_bound_vars());
assert!(!concrete_ty.has_escaping_bound_vars());
(opaque_ty, concrete_ty)
}
_ => continue,
};

let substs = opaque_ty.substs;
let opaque_type_key = OpaqueTypeKey { def_id: opaque_ty.def_id.expect_local(), substs };

let mut subst_regions = vec![self.universal_regions.fr_static];

let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
trace!(?vid);
let scc = self.constraint_sccs.scc(vid);
trace!(?scc);
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
}) {
Some(region) => {
let vid = self.universal_regions.to_region_vid(region);
subst_regions.push(vid);
region
}
None => {
subst_regions.push(vid);
infcx.tcx.mk_re_error_with_message(
DUMMY_SP,
"opaque type with non-universal region substs",
)
}
}
};

// Start by inserting universal regions from the member_constraint choice regions.
// This will ensure they get precedence when folding the regions in the concrete type.
if let Some(&ci) = member_constraints.get(&opaque_type_key) {
for &vid in self.member_constraints.choice_regions(ci) {
to_universal_region(vid, &mut subst_regions);
}
}
debug!(?subst_regions);

// Next, insert universal regions from substs, so we can translate regions that appear
// in them but are not subject to member constraints, for instance closure substs.
let universal_substs = infcx.tcx.fold_regions(substs, |region, _| {
if let ty::RePlaceholder(..) = region.kind() {
// Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
return region;
}
let vid = self.to_region_vid(region);
to_universal_region(vid, &mut subst_regions)
});
debug!(?universal_substs);
debug!(?subst_regions);

// Deduplicate the set of regions while keeping the chosen order.
let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>();
debug!(?subst_regions);

let universal_concrete_type =
infcx.tcx.fold_regions(concrete_ty, |region, _| match *region {
ty::ReVar(vid) => subst_regions
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
.unwrap_or(infcx.tcx.lifetimes.re_erased),
_ => region,
});
debug!(?universal_concrete_type);

let opaque_type_key =
OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
let ty = infcx.infer_opaque_definition_from_instantiation(
opaque_type_key,
OpaqueHiddenType { span: DUMMY_SP, ty: universal_concrete_type },
OpaqueTyOrigin::TyAlias,
);
// Sometimes two opaque types are the same only after we remap the generic parameters
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
// and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
// once we convert the generic parameters to those of the opaque type.
if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
if prev.ty != ty {
let guar = ty.error_reported().err().unwrap_or_else(|| {
prev.report_mismatch(&OpaqueHiddenType { ty, span: DUMMY_SP }, infcx.tcx)
});
prev.ty = infcx.tcx.ty_error(guar);
}
// Pick a better span if there is one.
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
prev.span = prev.span;
} else {
result.insert(opaque_type_key.def_id, OpaqueHiddenType { ty, span: DUMMY_SP });
}
}
result
}

/// Resolve any opaque types that were encountered while borrow checking
/// this item. This is then used to get the type in the `type_of` query.
///
Expand Down Expand Up @@ -60,8 +178,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
pub(crate) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
if infcx.tcx.trait_solver_next() {
assert!(opaque_ty_decls.is_empty());
return self.infer_opaque_types_next(infcx, param_env);
}
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();

let member_constraints: FxIndexMap<_, _> = self
Expand Down Expand Up @@ -263,6 +386,10 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
return self.tcx.ty_error(guar);
}

if self.tcx.trait_solver_next() {
return definition_ty;
}

// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
let OpaqueTyOrigin::TyAlias = origin else {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1480,6 +1480,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEvaluatable(_)
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::DefineOpaque(..)
| ty::PredicateKind::TypeWellFormedFromEnv(_)
| ty::PredicateKind::Ambiguous => bug!(),
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ fn check_opaque_meets_bounds<'tcx>(
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
if tcx.trait_solver_next() {
return;
}

let defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
hir::OpaqueTyOrigin::TyAlias => def_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ fn trait_predicate_kind<'tcx>(
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::DefineOpaque(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/outlives/explicit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::DefineOpaque(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// code is looking for a self type of an unresolved
// inference variable.
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::DefineOpaque(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
},
Expand Down
77 changes: 75 additions & 2 deletions compiler/rustc_hir_typeck/src/inherited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ 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::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
use rustc_span::{self, Span};
use rustc_span::{self, sym, Span};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _};
use rustc_type_ir::AliasKind;

use std::cell::RefCell;
use std::ops::Deref;
Expand Down Expand Up @@ -99,6 +102,76 @@ impl<'tcx> Inherited<'tcx> {
}
}

/// The `param_env` used to typeck this item.
///
/// `-Ztrait-solver=next` needs the inference context to construct
/// the `param_env` for typeck.
pub(super) fn typeck_param_env(&self, def_id: LocalDefId) -> ty::ParamEnv<'tcx> {
let tcx = self.tcx;
let param_env = tcx.param_env(def_id);
let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
param_env.without_const()
} else {
param_env
};

if tcx.trait_solver_next() {
let opaques = tcx.opaque_types_defined_by(def_id).subst_identity();
if !opaques.is_empty() {
let mut needed_item_bounds = Vec::new();

let define_opaques = opaques
.iter()
.map(|ty| match *ty.kind() {
ty::Alias(AliasKind::Opaque, alias_ty) => {
let def_id = alias_ty.def_id;
let ty_var = self.infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::OpaqueTypeInference(def_id),
span: self.tcx.def_span(def_id),
});

needed_item_bounds.push((
OpaqueTypeKey {
def_id: def_id.expect_local(),
substs: alias_ty.substs,
},
ty_var,
));
ty::PredicateKind::DefineOpaque(alias_ty, ty_var)
}
_ => bug!("unexpected defined opaque: {opaques:?}"),
})
.map(|kind| kind.to_predicate(tcx));

let param_env = ty::ParamEnv::new(
tcx.mk_predicates_from_iter(
param_env.caller_bounds().iter().chain(define_opaques),
),
param_env.reveal(),
param_env.constness(),
);

for (key, hidden_ty) in needed_item_bounds {
let mut obligations = Vec::new();
self.infcx.add_item_bounds_for_hidden_type(
key,
ObligationCause::dummy(),
param_env,
hidden_ty,
&mut obligations,
);
self.register_predicates(obligations);
}

param_env
} else {
param_env
}
} else {
param_env
}
}

#[instrument(level = "debug", skip(self))]
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
if obligation.has_escaping_bound_vars() {
Expand Down
12 changes: 4 additions & 8 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config;
use rustc_session::Session;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span};
use rustc_span::Span;

fluent_messages! { "../messages.ftl" }

Expand Down Expand Up @@ -189,14 +189,10 @@ fn typeck_with_fallback<'tcx>(
span_bug!(span, "can't type-check body of {:?}", def_id);
});
let body = tcx.hir().body(body_id);

let param_env = tcx.param_env(def_id);
let param_env = if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
param_env.without_const()
} else {
param_env
};
let inh = Inherited::new(tcx, def_id);
// `-Ztrait-solver=next` needs the inference context to construct
// the `param_env` for typeck.
let param_env = inh.typeck_param_env(def_id);
let mut fcx = FnCtxt::new(&inh, param_env, def_id);

if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::DefineOpaque(..)
| ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
Expand Down
31 changes: 30 additions & 1 deletion compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableEx
use rustc_middle::ty::TypeckResults;
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::{Span, DUMMY_SP};

use std::mem;
use std::ops::ControlFlow;
Expand Down Expand Up @@ -551,8 +551,37 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}

fn visit_opaque_types_next(&mut self) {
for predicate in self.fcx.param_env.caller_bounds() {
let (opaque_ty, hidden_ty) = match predicate.kind().skip_binder() {
ty::PredicateKind::DefineOpaque(opaque_ty, hidden_ty) => {
assert!(!opaque_ty.has_escaping_bound_vars());
assert!(!hidden_ty.has_escaping_bound_vars());
(opaque_ty, hidden_ty)
}
_ => continue,
};

let opaque_ty = self.resolve(opaque_ty, &DUMMY_SP);
let hidden_ty = self.resolve(hidden_ty, &DUMMY_SP);

self.typeck_results
.defined_opaque_types
.push(ty::DefinedOpaqueType { opaque_ty, hidden_ty });
}
}

#[instrument(skip(self), level = "debug")]
fn visit_opaque_types(&mut self) {
if self.tcx().trait_solver_next() {
let opaque_type_storage = self.fcx.infcx.take_opaque_types();
if !opaque_type_storage.is_empty() {
bug!("used old opaque type storage in new solver");
}

return self.visit_opaque_types_next();
}

let opaque_types = self.fcx.infcx.take_opaque_types();
for (opaque_type_key, decl) in opaque_types {
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
Expand Down
Loading