Skip to content

Commit 442862b

Browse files
committed
Don't build ParamEnv and do trait solving in ItemCtxts
1 parent 55d4364 commit 442862b

31 files changed

+576
-249
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,22 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3434
use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
3535
use rustc_middle::query::Providers;
3636
use rustc_middle::ty::util::{Discr, IntTypeExt};
37-
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions};
37+
use rustc_middle::ty::{
38+
self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions,
39+
};
3840
use rustc_middle::{bug, span_bug};
3941
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
4042
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
4143
use rustc_trait_selection::infer::InferCtxtExt;
42-
use rustc_trait_selection::traits::{ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations};
44+
use rustc_trait_selection::traits::{
45+
FulfillmentError, ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations,
46+
};
4347
use tracing::{debug, instrument};
4448

4549
use crate::errors;
46-
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
50+
use crate::hir_ty_lowering::{
51+
FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
52+
};
4753

4854
pub(crate) mod dump;
4955
mod generics_of;
@@ -364,6 +370,64 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
364370
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
365371
}
366372

373+
#[instrument(level = "debug", skip(self, _span), ret)]
374+
fn select_inherent_assoc_candidates(
375+
&self,
376+
_span: Span,
377+
self_ty: Ty<'tcx>,
378+
candidates: Vec<InherentAssocCandidate>,
379+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>) {
380+
assert!(!self_ty.has_infer());
381+
382+
// We don't just call the normal normalization routine here as we can't provide the
383+
// correct `ParamEnv` and it seems dubious to invoke arbitrary trait solving under
384+
// the wrong `ParamEnv`. Expanding free aliases doesn't need a `ParamEnv` so we do
385+
// this just to make resolution a little bit smarter.
386+
let self_ty = self.tcx.expand_free_alias_tys(self_ty);
387+
debug!("select_inherent_assoc_candidates: self_ty={:?}", self_ty);
388+
389+
// We make an infcx and replace any escaping vars with placeholders so that IAT res
390+
// with type/const bound vars in arguments is slightly smarter. `for<T> <Foo<T>>::IAT`
391+
// would otherwise unify with `impl Foo<u8>` when ideally we would not.
392+
let infcx = self.tcx().infer_ctxt().build(TypingMode::non_body_analysis());
393+
let mut universes = if self_ty.has_escaping_bound_vars() {
394+
vec![None; self_ty.outer_exclusive_binder().as_usize()]
395+
} else {
396+
vec![]
397+
};
398+
let candidates =
399+
rustc_trait_selection::traits::with_replaced_escaping_bound_vars(
400+
&infcx,
401+
&mut universes,
402+
self_ty,
403+
|self_ty| {
404+
candidates
405+
.into_iter()
406+
.filter(|&InherentAssocCandidate { impl_, .. }| {
407+
let impl_ty = self.tcx().type_of(impl_).instantiate_identity();
408+
409+
// See comment on doing this operation for `self_ty`
410+
let impl_ty = self.tcx.expand_free_alias_tys(impl_ty);
411+
debug!("select_inherent_assoc_candidates: impl_ty={:?}", impl_ty);
412+
413+
// We treat parameters in the self ty as rigid and parameters in the impl ty as infers
414+
// because it allows `impl<T> Foo<T>` to unify with `Foo<u8>::IAT`, while also disallowing
415+
// `Foo<T>::IAT` from unifying with `impl Foo<u8>`.
416+
//
417+
// We don't really care about a depth limit here because we're only working with user-written types
418+
// and if they wrote a type that would take hours to walk then that's kind of on them. On the other
419+
// hand the default depth limit is relatively low and could realistically be hit by users in normal
420+
// cases.
421+
ty::DeepRejectCtxt::relate_rigid_infer(self.tcx)
422+
.types_may_unify_with_depth(self_ty, impl_ty, usize::MAX)
423+
})
424+
.collect()
425+
},
426+
);
427+
428+
(candidates, vec![])
429+
}
430+
367431
fn lower_assoc_item_path(
368432
&self,
369433
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: 39 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,22 @@ 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::{DynCompatibilityViolation, ObligationCause};
36+
use rustc_infer::traits::DynCompatibilityViolation;
37+
use rustc_macros::{TypeFoldable, TypeVisitable};
3738
use rustc_middle::middle::stability::AllowUnstable;
3839
use rustc_middle::mir::interpret::LitToConstInput;
3940
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
4041
use rustc_middle::ty::{
41-
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
42-
TypeVisitableExt, TypingMode, Upcast, fold_regions,
42+
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
43+
TypingMode, Upcast, fold_regions,
4344
};
4445
use rustc_middle::{bug, span_bug};
4546
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
4647
use rustc_session::parse::feature_err;
4748
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
4849
use rustc_trait_selection::infer::InferCtxtExt;
4950
use rustc_trait_selection::traits::wf::object_region_bounds;
50-
use rustc_trait_selection::traits::{self, ObligationCtxt};
51+
use rustc_trait_selection::traits::{self, FulfillmentError};
5152
use tracing::{debug, instrument};
5253

5354
use crate::check::check_abi_fn_ptr;
@@ -99,6 +100,13 @@ pub enum RegionInferReason<'a> {
99100
OutlivesBound,
100101
}
101102

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

159+
fn select_inherent_assoc_candidates(
160+
&self,
161+
span: Span,
162+
self_ty: Ty<'tcx>,
163+
candidates: Vec<InherentAssocCandidate>,
164+
) -> (Vec<InherentAssocCandidate>, Vec<FulfillmentError<'tcx>>);
165+
151166
/// Lower a path to an associated item (of a trait) to a projection.
152167
///
153168
/// This method has to be defined by the concrete lowering context because
@@ -1449,48 +1464,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14491464
.filter_map(|&impl_| {
14501465
let (item, scope) =
14511466
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
1452-
Some((impl_, (item.def_id, scope)))
1467+
Some(InherentAssocCandidate { impl_, assoc_item: item.def_id, scope })
14531468
})
14541469
.collect();
14551470

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

1474-
// FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
1475-
// when inside of an ADT (#108491) or where clause.
1476-
let param_env = tcx.param_env(block.owner);
1474+
let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
1475+
match &applicable_candidates[..] {
1476+
&[] => Err(self.report_unresolved_inherent_assoc_item(
1477+
name,
1478+
self_ty,
1479+
candidates,
1480+
fulfillment_errors,
1481+
span,
1482+
assoc_tag,
1483+
)),
14771484

1478-
let mut universes = if self_ty.has_escaping_bound_vars() {
1479-
vec![None; self_ty.outer_exclusive_binder().as_usize()]
1480-
} else {
1481-
vec![]
1482-
};
1485+
&[applicable_candidate] => Ok(applicable_candidate),
14831486

1484-
let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars(
1485-
infcx,
1486-
&mut universes,
1487-
self_ty,
1488-
|self_ty| {
1489-
self.select_inherent_assoc_candidates(
1490-
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
1491-
)
1492-
},
1493-
)?;
1487+
&[_, ..] => Err(self.report_ambiguous_inherent_assoc_item(
1488+
name,
1489+
candidates.into_iter().map(|cand| cand.assoc_item).collect(),
1490+
span,
1491+
)),
1492+
}?;
14941493

14951494
self.check_assoc_item(assoc_item, name, def_scope, block, span);
14961495

@@ -1507,78 +1506,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
15071506
Ok(Some((assoc_item, args)))
15081507
}
15091508

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

0 commit comments

Comments
 (0)