Skip to content

Commit 20fb8ab

Browse files
committed
Fix overlapping impls
1 parent e612e26 commit 20fb8ab

File tree

6 files changed

+215
-172
lines changed

6 files changed

+215
-172
lines changed

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_middle/src/ty/abstract_const.rs

+29-137
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! A subset of a mir body used for const evaluatability checking.
22
use crate::mir;
3+
use crate::ty::visit::TypeVisitable;
34
use crate::ty::{self, subst::Subst, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
45
use rustc_errors::ErrorGuaranteed;
5-
use std::iter;
6+
use rustc_hir::def_id::DefId;
7+
use std::cmp;
68
use std::ops::ControlFlow;
79

810
rustc_index::newtype_index! {
@@ -63,6 +65,31 @@ impl<'tcx> AbstractConst<'tcx> {
6365
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node,
6466
}
6567
}
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+
}
6693
}
6794

6895
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
@@ -104,7 +131,7 @@ impl<'tcx> TyCtxt<'tcx> {
104131
#[inline]
105132
pub fn thir_abstract_const_opt_const_arg(
106133
self,
107-
def: ty::WithOptConstParam<rustc_hir::def_id::DefId>,
134+
def: ty::WithOptConstParam<DefId>,
108135
) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorGuaranteed> {
109136
if let Some((did, param_did)) = def.as_const_arg() {
110137
self.thir_abstract_const_of_const_arg((did, param_did))
@@ -114,28 +141,6 @@ impl<'tcx> TyCtxt<'tcx> {
114141
}
115142
}
116143

117-
#[instrument(skip(tcx), level = "debug")]
118-
pub fn try_unify_abstract_consts<'tcx>(
119-
tcx: TyCtxt<'tcx>,
120-
(a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
121-
param_env: ty::ParamEnv<'tcx>,
122-
) -> bool {
123-
(|| {
124-
if let Some(a) = AbstractConst::new(tcx, a)? {
125-
if let Some(b) = AbstractConst::new(tcx, b)? {
126-
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
127-
return Ok(const_unify_ctxt.try_unify(a, b));
128-
}
129-
}
130-
131-
Ok(false)
132-
})()
133-
.unwrap_or_else(|_: ErrorGuaranteed| true)
134-
// FIXME(generic_const_exprs): We should instead have this
135-
// method return the resulting `ty::Const` and return `ConstKind::Error`
136-
// on `ErrorGuaranteed`.
137-
}
138-
139144
#[instrument(skip(tcx, f), level = "debug")]
140145
pub fn walk_abstract_const<'tcx, R, F>(
141146
tcx: TyCtxt<'tcx>,
@@ -172,119 +177,6 @@ where
172177
recurse(tcx, ct, &mut f)
173178
}
174179

175-
pub struct ConstUnifyCtxt<'tcx> {
176-
pub tcx: TyCtxt<'tcx>,
177-
pub param_env: ty::ParamEnv<'tcx>,
178-
}
179-
180-
impl<'tcx> ConstUnifyCtxt<'tcx> {
181-
// Substitutes generics repeatedly to allow AbstractConsts to unify where a
182-
// ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g.
183-
// Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
184-
#[inline]
185-
#[instrument(skip(self), level = "debug")]
186-
fn try_replace_substs_in_root(
187-
&self,
188-
mut abstr_const: AbstractConst<'tcx>,
189-
) -> Option<AbstractConst<'tcx>> {
190-
while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
191-
match AbstractConst::from_const(self.tcx, ct) {
192-
Ok(Some(act)) => abstr_const = act,
193-
Ok(None) => break,
194-
Err(_) => return None,
195-
}
196-
}
197-
198-
Some(abstr_const)
199-
}
200-
201-
/// Tries to unify two abstract constants using structural equality.
202-
#[instrument(skip(self), level = "debug")]
203-
pub fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
204-
let a = if let Some(a) = self.try_replace_substs_in_root(a) {
205-
a
206-
} else {
207-
return true;
208-
};
209-
210-
let b = if let Some(b) = self.try_replace_substs_in_root(b) {
211-
b
212-
} else {
213-
return true;
214-
};
215-
216-
let a_root = a.root(self.tcx);
217-
let b_root = b.root(self.tcx);
218-
debug!(?a_root, ?b_root);
219-
220-
match (a_root, b_root) {
221-
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
222-
let a_ct = a_ct.eval(self.tcx, self.param_env);
223-
debug!("a_ct evaluated: {:?}", a_ct);
224-
let b_ct = b_ct.eval(self.tcx, self.param_env);
225-
debug!("b_ct evaluated: {:?}", b_ct);
226-
227-
if a_ct.ty() != b_ct.ty() {
228-
return false;
229-
}
230-
231-
match (a_ct.kind(), b_ct.kind()) {
232-
// We can just unify errors with everything to reduce the amount of
233-
// emitted errors here.
234-
(ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
235-
(ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
236-
a_param == b_param
237-
}
238-
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
239-
// If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
240-
// we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
241-
// means that we only allow inference variables if they are equal.
242-
(ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
243-
// We expand generic anonymous constants at the start of this function, so this
244-
// branch should only be taking when dealing with associated constants, at
245-
// which point directly comparing them seems like the desired behavior.
246-
//
247-
// FIXME(generic_const_exprs): This isn't actually the case.
248-
// We also take this branch for concrete anonymous constants and
249-
// expand generic anonymous constants with concrete substs.
250-
(ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
251-
a_uv == b_uv
252-
}
253-
// FIXME(generic_const_exprs): We may want to either actually try
254-
// to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
255-
// this, for now we just return false here.
256-
_ => false,
257-
}
258-
}
259-
(Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
260-
self.try_unify(a.subtree(al), b.subtree(bl))
261-
&& self.try_unify(a.subtree(ar), b.subtree(br))
262-
}
263-
(Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
264-
self.try_unify(a.subtree(av), b.subtree(bv))
265-
}
266-
(Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
267-
if a_args.len() == b_args.len() =>
268-
{
269-
self.try_unify(a.subtree(a_f), b.subtree(b_f))
270-
&& iter::zip(a_args, b_args)
271-
.all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn)))
272-
}
273-
(Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
274-
if (a_ty == b_ty) && (a_kind == b_kind) =>
275-
{
276-
self.try_unify(a.subtree(a_operand), b.subtree(b_operand))
277-
}
278-
// use this over `_ => false` to make adding variants to `Node` less error prone
279-
(Node::Cast(..), _)
280-
| (Node::FunctionCall(..), _)
281-
| (Node::UnaryOp(..), _)
282-
| (Node::Binop(..), _)
283-
| (Node::Leaf(..), _) => false,
284-
}
285-
}
286-
}
287-
288180
// We were unable to unify the abstract constant with
289181
// a constant found in the caller bounds, there are
290182
// now three possible cases here.

0 commit comments

Comments
 (0)