Skip to content

Commit 3f04713

Browse files
committed
Don't build ParamEnv and do trait solving in ItemCtxts
1 parent 13718eb commit 3f04713

35 files changed

+588
-270
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,22 @@ use rustc_infer::traits::{DynCompatibilityViolation, 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, hir_ty_lowering_dyn_compatibility_violations};
45+
use rustc_trait_selection::traits::{
46+
FulfillmentError, ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations,
47+
};
4448
use tracing::{debug, instrument};
4549

4650
use crate::errors;
47-
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
51+
use crate::hir_ty_lowering::{
52+
FeedConstTy, HirTyLowerer, InherentAssocCandidate, RegionInferReason,
53+
};
4854

4955
pub(crate) mod dump;
5056
mod generics_of;
@@ -444,6 +450,64 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
444450
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
445451
}
446452

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

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

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

1474-
let mut universes = if self_ty.has_escaping_bound_vars() {
1475-
vec![None; self_ty.outer_exclusive_binder().as_usize()]
1476-
} else {
1477-
vec![]
1478-
};
1481+
&[applicable_candidate] => Ok(applicable_candidate),
14791482

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

14911490
self.check_assoc_item(assoc_item, name, def_scope, block, span);
14921491

@@ -1503,78 +1502,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
15031502
Ok(Some((assoc_item, args)))
15041503
}
15051504

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

0 commit comments

Comments
 (0)