Skip to content

Commit ecae3d7

Browse files
authored
Rollup merge of #99000 - JulianKnodt:allow_resolve_no_substs, r=lcnr
Move abstract const to middle Moves AbstractConst (and all associated methods) to rustc middle for use in `rustc_infer`. This allows for const resolution in infer to use abstract consts to walk consts and check if they are resolvable. This attempts to resolve the issue where `Foo<{ concrete const }, generic T>` is incorrectly marked as conflicting, and is independent from the other issue where nested abstract consts must be resolved. r? `@lcnr`
2 parents 8c5c983 + 20fb8ab commit ecae3d7

File tree

24 files changed

+799
-750
lines changed

24 files changed

+799
-750
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4514,6 +4514,7 @@ dependencies = [
45144514
"rustc_data_structures",
45154515
"rustc_errors",
45164516
"rustc_hir",
4517+
"rustc_index",
45174518
"rustc_infer",
45184519
"rustc_middle",
45194520
"rustc_session",

compiler/rustc_infer/src/infer/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
2121
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
2222
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
2323
use rustc_middle::traits::select;
24+
use rustc_middle::ty::abstract_const::AbstractConst;
2425
use rustc_middle::ty::error::{ExpectedFound, TypeError};
2526
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
2627
use rustc_middle::ty::relate::RelateResult;
@@ -1651,14 +1652,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16511652
unevaluated: ty::Unevaluated<'tcx>,
16521653
span: Option<Span>,
16531654
) -> EvalToValTreeResult<'tcx> {
1654-
let substs = self.resolve_vars_if_possible(unevaluated.substs);
1655+
let mut substs = self.resolve_vars_if_possible(unevaluated.substs);
16551656
debug!(?substs);
16561657

16571658
// Postpone the evaluation of constants whose substs depend on inference
16581659
// variables
16591660
if substs.has_infer_types_or_consts() {
1660-
debug!("substs have infer types or consts: {:?}", substs);
1661-
return Err(ErrorHandled::TooGeneric);
1661+
let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
1662+
if let Ok(None) = ac {
1663+
substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
1664+
} else {
1665+
return Err(ErrorHandled::TooGeneric);
1666+
}
16621667
}
16631668

16641669
let param_env_erased = self.tcx.erase_regions(param_env);

compiler/rustc_metadata/src/rmeta/decoder.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc_index::vec::{Idx, IndexVec};
2121
use rustc_middle::metadata::ModChild;
2222
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
2323
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
24-
use rustc_middle::thir;
2524
use rustc_middle::ty::codec::TyDecoder;
2625
use rustc_middle::ty::fast_reject::SimplifiedType;
2726
use rustc_middle::ty::GeneratorDiagnosticData;
@@ -638,7 +637,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
638637
}
639638
}
640639

641-
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
640+
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [ty::abstract_const::Node<'tcx>] {
642641
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
643642
ty::codec::RefDecodable::decode(d)
644643
}

compiler/rustc_metadata/src/rmeta/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use rustc_middle::metadata::ModChild;
1717
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
1818
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
1919
use rustc_middle::mir;
20-
use rustc_middle::thir;
2120
use rustc_middle::ty::fast_reject::SimplifiedType;
2221
use rustc_middle::ty::query::Providers;
2322
use rustc_middle::ty::{self, ReprOptions, Ty};
@@ -361,7 +360,7 @@ define_tables! {
361360
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
362361
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
363362
// FIXME(compiler-errors): Why isn't this a LazyArray?
364-
thir_abstract_const: Table<DefIndex, LazyValue<&'static [thir::abstract_const::Node<'static>]>>,
363+
thir_abstract_const: Table<DefIndex, LazyValue<&'static [ty::abstract_const::Node<'static>]>>,
365364
impl_parent: Table<DefIndex, RawDefId>,
366365
impl_polarity: Table<DefIndex, ty::ImplPolarity>,
367366
constness: Table<DefIndex, hir::Constness>,

compiler/rustc_middle/src/query/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ rustc_queries! {
351351
/// Try to build an abstract representation of the given constant.
352352
query thir_abstract_const(
353353
key: DefId
354-
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
354+
) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
355355
desc {
356356
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
357357
}
@@ -360,7 +360,7 @@ rustc_queries! {
360360
/// Try to build an abstract representation of the given constant.
361361
query thir_abstract_const_of_const_arg(
362362
key: (LocalDefId, DefId)
363-
) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
363+
) -> Result<Option<&'tcx [ty::abstract_const::Node<'tcx>]>, ErrorGuaranteed> {
364364
desc {
365365
|tcx|
366366
"building an abstract representation for the const argument {}",

compiler/rustc_middle/src/thir.rs

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
3030
use std::fmt;
3131
use std::ops::Index;
3232

33-
pub mod abstract_const;
3433
pub mod visit;
3534

3635
newtype_index! {

compiler/rustc_middle/src/thir/abstract_const.rs

-61
This file was deleted.

compiler/rustc_middle/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mod structural_impls;
1010
pub mod util;
1111

1212
use crate::infer::canonical::Canonical;
13-
use crate::thir::abstract_const::NotConstEvaluatable;
13+
use crate::ty::abstract_const::NotConstEvaluatable;
1414
use crate::ty::subst::SubstsRef;
1515
use crate::ty::{self, AdtKind, Ty, TyCtxt};
1616

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
//! A subset of a mir body used for const evaluatability checking.
2+
use crate::mir;
3+
use crate::ty::visit::TypeVisitable;
4+
use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
5+
use rustc_errors::ErrorGuaranteed;
6+
use rustc_hir::def_id::DefId;
7+
use std::cmp;
8+
use std::ops::ControlFlow;
9+
10+
rustc_index::newtype_index! {
11+
/// An index into an `AbstractConst`.
12+
pub struct NodeId {
13+
derive [HashStable]
14+
DEBUG_FORMAT = "n{}",
15+
}
16+
}
17+
18+
/// A tree representing an anonymous constant.
19+
///
20+
/// This is only able to represent a subset of `MIR`,
21+
/// and should not leak any information about desugarings.
22+
#[derive(Debug, Clone, Copy)]
23+
pub struct AbstractConst<'tcx> {
24+
// FIXME: Consider adding something like `IndexSlice`
25+
// and use this here.
26+
inner: &'tcx [Node<'tcx>],
27+
substs: SubstsRef<'tcx>,
28+
}
29+
30+
impl<'tcx> AbstractConst<'tcx> {
31+
pub fn new(
32+
tcx: TyCtxt<'tcx>,
33+
uv: ty::Unevaluated<'tcx, ()>,
34+
) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
35+
let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
36+
debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
37+
Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) }))
38+
}
39+
40+
pub fn from_const(
41+
tcx: TyCtxt<'tcx>,
42+
ct: ty::Const<'tcx>,
43+
) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
44+
match ct.kind() {
45+
ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
46+
ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
47+
_ => Ok(None),
48+
}
49+
}
50+
51+
#[inline]
52+
pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> {
53+
AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs }
54+
}
55+
56+
#[inline]
57+
pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> {
58+
let node = self.inner.last().copied().unwrap();
59+
match node {
60+
Node::Leaf(leaf) => Node::Leaf(EarlyBinder(leaf).subst(tcx, self.substs)),
61+
Node::Cast(kind, operand, ty) => {
62+
Node::Cast(kind, operand, EarlyBinder(ty).subst(tcx, self.substs))
63+
}
64+
// Don't perform substitution on the following as they can't directly contain generic params
65+
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
66+
}
67+
}
68+
69+
pub fn unify_failure_kind(self, tcx: TyCtxt<'tcx>) -> FailureKind {
70+
let mut failure_kind = FailureKind::Concrete;
71+
walk_abstract_const::<!, _>(tcx, self, |node| {
72+
match node.root(tcx) {
73+
Node::Leaf(leaf) => {
74+
if leaf.has_infer_types_or_consts() {
75+
failure_kind = FailureKind::MentionsInfer;
76+
} else if leaf.has_param_types_or_consts() {
77+
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
78+
}
79+
}
80+
Node::Cast(_, _, ty) => {
81+
if ty.has_infer_types_or_consts() {
82+
failure_kind = FailureKind::MentionsInfer;
83+
} else if ty.has_param_types_or_consts() {
84+
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
85+
}
86+
}
87+
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {}
88+
}
89+
ControlFlow::CONTINUE
90+
});
91+
failure_kind
92+
}
93+
}
94+
95+
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
96+
pub enum CastKind {
97+
/// thir::ExprKind::As
98+
As,
99+
/// thir::ExprKind::Use
100+
Use,
101+
}
102+
103+
/// A node of an `AbstractConst`.
104+
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
105+
pub enum Node<'tcx> {
106+
Leaf(ty::Const<'tcx>),
107+
Binop(mir::BinOp, NodeId, NodeId),
108+
UnaryOp(mir::UnOp, NodeId),
109+
FunctionCall(NodeId, &'tcx [NodeId]),
110+
Cast(CastKind, NodeId, Ty<'tcx>),
111+
}
112+
113+
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
114+
pub enum NotConstEvaluatable {
115+
Error(ErrorGuaranteed),
116+
MentionsInfer,
117+
MentionsParam,
118+
}
119+
120+
impl From<ErrorGuaranteed> for NotConstEvaluatable {
121+
fn from(e: ErrorGuaranteed) -> NotConstEvaluatable {
122+
NotConstEvaluatable::Error(e)
123+
}
124+
}
125+
126+
TrivialTypeTraversalAndLiftImpls! {
127+
NotConstEvaluatable,
128+
}
129+
130+
impl<'tcx> TyCtxt<'tcx> {
131+
#[inline]
132+
pub fn thir_abstract_const_opt_const_arg(
133+
self,
134+
def: ty::WithOptConstParam<DefId>,
135+
) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> {
136+
if let Some((did, param_did)) = def.as_const_arg() {
137+
self.thir_abstract_const_of_const_arg((did, param_did))
138+
} else {
139+
self.thir_abstract_const(def.did)
140+
}
141+
}
142+
}
143+
144+
#[instrument(skip(tcx, f), level = "debug")]
145+
pub fn walk_abstract_const<'tcx, R, F>(
146+
tcx: TyCtxt<'tcx>,
147+
ct: AbstractConst<'tcx>,
148+
mut f: F,
149+
) -> ControlFlow<R>
150+
where
151+
F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
152+
{
153+
#[instrument(skip(tcx, f), level = "debug")]
154+
fn recurse<'tcx, R>(
155+
tcx: TyCtxt<'tcx>,
156+
ct: AbstractConst<'tcx>,
157+
f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
158+
) -> ControlFlow<R> {
159+
f(ct)?;
160+
let root = ct.root(tcx);
161+
debug!(?root);
162+
match root {
163+
Node::Leaf(_) => ControlFlow::CONTINUE,
164+
Node::Binop(_, l, r) => {
165+
recurse(tcx, ct.subtree(l), f)?;
166+
recurse(tcx, ct.subtree(r), f)
167+
}
168+
Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f),
169+
Node::FunctionCall(func, args) => {
170+
recurse(tcx, ct.subtree(func), f)?;
171+
args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
172+
}
173+
Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
174+
}
175+
}
176+
177+
recurse(tcx, ct, &mut f)
178+
}
179+
180+
// We were unable to unify the abstract constant with
181+
// a constant found in the caller bounds, there are
182+
// now three possible cases here.
183+
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
184+
pub enum FailureKind {
185+
/// The abstract const still references an inference
186+
/// variable, in this case we return `TooGeneric`.
187+
MentionsInfer,
188+
/// The abstract const references a generic parameter,
189+
/// this means that we emit an error here.
190+
MentionsParam,
191+
/// The substs are concrete enough that we can simply
192+
/// try and evaluate the given constant.
193+
Concrete,
194+
}

compiler/rustc_middle/src/ty/codec.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::mir::{
1212
self,
1313
interpret::{AllocId, ConstAllocation},
1414
};
15-
use crate::thir;
1615
use crate::traits;
1716
use crate::ty::subst::SubstsRef;
1817
use crate::ty::{self, AdtDef, Ty};
@@ -346,7 +345,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
346345
}
347346

348347
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
349-
for [thir::abstract_const::Node<'tcx>]
348+
for [ty::abstract_const::Node<'tcx>]
350349
{
351350
fn decode(decoder: &mut D) -> &'tcx Self {
352351
decoder.interner().arena.alloc_from_iter(
@@ -356,7 +355,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
356355
}
357356

358357
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
359-
for [thir::abstract_const::NodeId]
358+
for [ty::abstract_const::NodeId]
360359
{
361360
fn decode(decoder: &mut D) -> &'tcx Self {
362361
decoder.interner().arena.alloc_from_iter(

compiler/rustc_middle/src/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub use self::sty::{
9292
pub use self::trait_def::TraitDef;
9393

9494
pub mod _match;
95+
pub mod abstract_const;
9596
pub mod adjustment;
9697
pub mod binding;
9798
pub mod cast;

0 commit comments

Comments
 (0)