Skip to content

Commit ccec360

Browse files
committed
Don't build ParamEnv and do trait solving in ItemCtxts
1 parent 52bf0cf commit ccec360

35 files changed

+585
-270
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,20 @@ use rustc_infer::traits::ObligationCause;
3535
use rustc_middle::hir::nested_filter;
3636
use rustc_middle::query::Providers;
3737
use rustc_middle::ty::util::{Discr, IntTypeExt};
38-
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions};
38+
use rustc_middle::ty::{
39+
self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions,
40+
};
3941
use rustc_middle::{bug, span_bug};
4042
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
4143
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
4244
use rustc_trait_selection::infer::InferCtxtExt;
43-
use rustc_trait_selection::traits::ObligationCtxt;
45+
use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
4446
use tracing::{debug, instrument};
4547

4648
use crate::errors;
47-
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
49+
use crate::hir_ty_lowering::{
50+
FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
51+
};
4852

4953
pub(crate) mod dump;
5054
mod generics_of;
@@ -444,6 +448,64 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
444448
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
445449
}
446450

451+
#[instrument(level = "debug", skip(self, _span), ret)]
452+
fn select_inherent_assoc_candidates(
453+
&self,
454+
_span: Span,
455+
self_ty: Ty<'tcx>,
456+
candidates: Vec<InherentAssocCandidate>,
457+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
458+
assert!(!self_ty.has_infer());
459+
460+
// We don't just call the normal normalization routine here as we can't provide the
461+
// correct `ParamEnv` and it seems dubious to invoke arbitrary trait solving under
462+
// the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do
463+
// this just to make resolution a little bit smarter.
464+
let self_ty = self.tcx.expand_free_alias_tys(self_ty);
465+
debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty);
466+
467+
// We make an infcx and replace any escaping vars with placeholders so that IAT res
468+
// with type/const bound vars in arguments is slightly smarter. `for<T> <Foo<T>>::IAT`
469+
// would otherwise unify with `impl Foo<u8>` when ideally we would not.
470+
let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis());
471+
let mut universes = if self_ty.has_escaping_bound_vars() {
472+
vec![None; self_ty.outer_exclusive_binder().as_usize()]
473+
} else {
474+
vec![]
475+
};
476+
let candidates =
477+
rustc_trait_selection::traits::with_replaced_escaping_bound_vars(
478+
&infcx,
479+
&mut universes,
480+
self_ty,
481+
|self_ty| {
482+
candidates
483+
.into_iter()
484+
.filter(|&InherentAssocCandidate { impl_, .. }| {
485+
let impl_ty = self.tcx().type_of(impl_).instantiate_identity();
486+
487+
// See comment on doing this operation for `self_ty`
488+
let impl_ty = self.tcx.expand_free_alias_tys(impl_ty);
489+
debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty);
490+
491+
// We treat parameters in the self ty as rigid and parameters in the impl ty as infers
492+
// because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing
493+
// `Foo<T>::IAT` from unifying with `impl Foo<u8>`.
494+
//
495+
// We don't really care about a depth limit here because we're only working with user-written types
496+
// and if they wrote a type that would take hours to walk then that's kind of on them. On the other
497+
// hand the default depth limit is relatively low and could realistically be hit by users in normal
498+
// cases.
499+
ty::DeepRejectCtxt::relate_rigid_infer(self.tcx)
500+
.types_may_unify_with_depth(self_ty, impl_ty, usize::MAX)
501+
})
502+
.collect()
503+
},
504+
);
505+
506+
(candidates, vec![])
507+
}
508+
447509
fn lower_assoc_item_path(
448510
&self,
449511
span: Span,

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc_trait_selection::traits::{
2626
use smallvec::SmallVec;
2727
use tracing::debug;
2828

29+
use super::InherentAssocCandidate;
2930
use crate::errors::{
3031
self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams,
3132
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
@@ -742,7 +743,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
742743
&self,
743744
name: Ident,
744745
self_ty: Ty<'tcx>,
745-
candidates: Vec<(DefId, (DefId, DefId))>,
746+
candidates: Vec<InherentAssocCandidate>,
746747
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
747748
span: Span,
748749
assoc_tag: ty::AssocTag,
@@ -776,8 +777,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
776777
let type_candidates = candidates
777778
.iter()
778779
.take(limit)
779-
.map(|&(impl_, _)| {
780-
format!("- `{}`", tcx.at(span).type_of(impl_).instantiate_identity())
780+
.map(|cand| {
781+
format!("- `{}`", tcx.at(span).type_of(cand.impl_).instantiate_identity())
781782
})
782783
.collect::<Vec<_>>()
783784
.join("\n");

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 38 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,21 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
3333
use rustc_hir::def_id::{DefId, LocalDefId};
3434
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
3535
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
36-
use rustc_infer::traits::ObligationCause;
36+
use rustc_macros::{TypeFoldable, TypeVisitable};
3737
use rustc_middle::middle::stability::AllowUnstable;
3838
use rustc_middle::mir::interpret::LitToConstInput;
3939
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
4040
use rustc_middle::ty::{
41-
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
42-
TypeVisitableExt, TypingMode, Upcast, fold_regions,
41+
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
42+
TypingMode, Upcast, fold_regions,
4343
};
4444
use rustc_middle::{bug, span_bug};
4545
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
4646
use rustc_session::parse::feature_err;
4747
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
4848
use rustc_trait_selection::infer::InferCtxtExt;
4949
use rustc_trait_selection::traits::wf::object_region_bounds;
50-
use rustc_trait_selection::traits::{self, ObligationCtxt};
50+
use rustc_trait_selection::traits::{self, FulfillmentError};
5151
use tracing::{debug, instrument};
5252

5353
use crate::check::check_abi_fn_ptr;
@@ -99,6 +99,13 @@ pub enum RegionInferReason<'a> {
9999
OutlivesBound,
100100
}
101101

102+
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Debug)]
103+
pub struct InherentAssocCandidate {
104+
pub impl_: DefId,
105+
pub assoc_item: DefId,
106+
pub scope: DefId,
107+
}
108+
102109
/// A context which can lower type-system entities from the [HIR][hir] to
103110
/// the [`rustc_middle::ty`] representation.
104111
///
@@ -148,6 +155,13 @@ pub trait HirTyLowerer<'tcx> {
148155
assoc_ident: Ident,
149156
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>;
150157

158+
fn select_inherent_assoc_candidates(
159+
&self,
160+
span: Span,
161+
self_ty: Ty<'tcx>,
162+
candidates: Vec<InherentAssocCandidate>,
163+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>);
164+
151165
/// Lower a path to an associated item (of a trait) to a projection.
152166
///
153167
/// This method has to be defined by the concrete lowering context because
@@ -1441,48 +1455,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14411455
.filter_map(|&impl_| {
14421456
let (item, scope) =
14431457
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
1444-
Some((impl_, (item.def_id, scope)))
1458+
Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope })
14451459
})
14461460
.collect();
14471461

1448-
if candidates.is_empty() {
1449-
return Ok(None);
1450-
}
1451-
1452-
//
1453-
// Select applicable inherent associated type candidates modulo regions.
1454-
//
1455-
1456-
// In contexts that have no inference context, just make a new one.
1457-
// We do need a local variable to store it, though.
1458-
let infcx = match self.infcx() {
1459-
Some(infcx) => infcx,
1460-
None => {
1461-
assert!(!self_ty.has_infer());
1462-
&tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis())
1463-
}
1464-
};
1462+
let (applicable_candidates, fulfillment_errors) =
1463+
self.select_inherent_assoc_candidates(span, self_ty, candidates.clone());
14651464

1466-
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
1467-
// when inside of an ADT (#108491) or where clause.
1468-
let param_env = tcx.param_env(block.owner);
1465+
let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
1466+
match &applicable_candidates[..] {
1467+
&[] => Err(self.report_unresolved_inherent_assoc_item(
1468+
name,
1469+
self_ty,
1470+
candidates,
1471+
fulfillment_errors,
1472+
span,
1473+
assoc_tag,
1474+
)),
14691475

1470-
let mut universes = if self_ty.has_escaping_bound_vars() {
1471-
vec![None; self_ty.outer_exclusive_binder().as_usize()]
1472-
} else {
1473-
vec![]
1474-
};
1476+
&[applicable_candidate] => Ok(applicable_candidate),
14751477

1476-
let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars(
1477-
infcx,
1478-
&mut universes,
1479-
self_ty,
1480-
|self_ty| {
1481-
self.select_inherent_assoc_candidates(
1482-
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
1483-
)
1484-
},
1485-
)?;
1478+
&[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
1479+
name,
1480+
candidates.into_iter().map(|cand| cand.assoc_item).collect(),
1481+
span,
1482+
)),
1483+
}?;
14861484

14871485
self.check_assoc_item(assoc_item, name, def_scope, block, span);
14881486

@@ -1499,78 +1497,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14991497
Ok(Some((assoc_item, args)))
15001498
}
15011499

1502-
fn select_inherent_assoc_candidates(
1503-
&self,
1504-
infcx: &InferCtxt<'tcx>,
1505-
name: Ident,
1506-
span: Span,
1507-
self_ty: Ty<'tcx>,
1508-
param_env: ParamEnv<'tcx>,
1509-
candidates: Vec<(DefId, (DefId, DefId))>,
1510-
assoc_tag: ty::AssocTag,
1511-
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
1512-
let tcx = self.tcx();
1513-
let mut fulfillment_errors = Vec::new();
1514-
1515-
let applicable_candidates: Vec<_> = candidates
1516-
.iter()
1517-
.copied()
1518-
.filter(|&(impl_, _)| {
1519-
infcx.probe(|_| {
1520-
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
1521-
let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty);
1522-
1523-
let impl_args = infcx.fresh_args_for_item(span, impl_);
1524-
let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args);
1525-
let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty);
1526-
1527-
// Check that the self types can be related.
1528-
if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() {
1529-
return false;
1530-
}
1531-
1532-
// Check whether the impl imposes obligations we have to worry about.
1533-
let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args);
1534-
let impl_bounds =
1535-
ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds);
1536-
let impl_obligations = traits::predicates_for_generics(
1537-
|_, _| ObligationCause::dummy(),
1538-
param_env,
1539-
impl_bounds,
1540-
);
1541-
ocx.register_obligations(impl_obligations);
1542-
1543-
let mut errors = ocx.select_where_possible();
1544-
if !errors.is_empty() {
1545-
fulfillment_errors.append(&mut errors);
1546-
return false;
1547-
}
1548-
1549-
true
1550-
})
1551-
})
1552-
.collect();
1553-
1554-
match &applicable_candidates[..] {
1555-
&[] => Err(self.report_unresolved_inherent_assoc_item(
1556-
name,
1557-
self_ty,
1558-
candidates,
1559-
fulfillment_errors,
1560-
span,
1561-
assoc_tag,
1562-
)),
1563-
1564-
&[applicable_candidate] => Ok(applicable_candidate),
1565-
1566-
&[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
1567-
name,
1568-
applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
1569-
span,
1570-
)),
1571-
}
1572-
}
1573-
15741500
/// Given name and kind search for the assoc item in the provided scope and check if it's accessible[^1].
15751501
///
15761502
/// [^1]: I.e., accessible in the provided scope wrt. visibility and stability.

0 commit comments

Comments
 (0)