Skip to content

Commit eab581e

Browse files
committed
Fully implement ConstArgHasType
1 parent bdfe036 commit eab581e

File tree

6 files changed

+148
-50
lines changed

6 files changed

+148
-50
lines changed

compiler/rustc_middle/src/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ pub enum SelectionError<'tcx> {
616616
/// We can thus not know whether the hidden type implements an auto trait, so
617617
/// we should not presume anything about it.
618618
OpaqueTypeAutoTraitLeakageUnknown(DefId),
619+
/// Error for a `ConstArgHasType` goal
620+
ConstArgHasWrongType(ty::Const<'tcx>, Ty<'tcx>, Ty<'tcx>),
619621
}
620622

621623
#[derive(Clone, Debug, TypeVisitable)]

compiler/rustc_middle/src/ty/sty.rs

+22
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_span::symbol::{sym, Symbol};
2121
use rustc_span::{Span, DUMMY_SP};
2222
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
2323
use rustc_target::spec::abi;
24+
use rustc_type_ir::visit::TypeVisitableExt;
2425
use std::assert_matches::debug_assert_matches;
2526
use std::borrow::Cow;
2627
use std::iter;
@@ -339,6 +340,27 @@ impl ParamConst {
339340
pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
340341
ParamConst::new(def.index, def.name)
341342
}
343+
344+
pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
345+
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
346+
// `ConstArgHasType` are never desugared to be higher ranked.
347+
match clause.kind().skip_binder() {
348+
ty::ClauseKind::ConstArgHasType(param_ct, ty) => {
349+
assert!(!(param_ct, ty).has_escaping_bound_vars());
350+
351+
match param_ct.kind() {
352+
ty::ConstKind::Param(param_ct) if param_ct.index == self.index => Some(ty),
353+
_ => None,
354+
}
355+
}
356+
_ => None,
357+
}
358+
});
359+
360+
let ty = candidates.next().unwrap();
361+
assert!(candidates.next().is_none());
362+
ty
363+
}
342364
}
343365

344366
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]

compiler/rustc_trait_selection/src/solve/mod.rs

+46-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_middle::traits::solve::{
2525
};
2626
use rustc_middle::ty::{
2727
self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty,
28-
TyCtxt, TypeOutlivesPredicate, UniverseIndex,
28+
TyCtxt, TypeOutlivesPredicate, TypeVisitableExt, UniverseIndex,
2929
};
3030

3131
mod alias_relate;
@@ -208,22 +208,58 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
208208
// We do still stall on infer vars though as otherwise a goal like:
209209
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
210210
// get unified with some const that is not of type `usize`.
211-
match ct.kind() {
211+
let ct_ty = match ct.kind() {
212212
// FIXME: Ignore effect vars because canonicalization doesn't handle them correctly
213213
// and if we stall on the var then we wind up creating ambiguity errors in a probe
214214
// for this goal which contains an effect var. Which then ends up ICEing.
215-
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
216-
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
215+
ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
216+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
217+
}
218+
ty::ConstKind::Infer(_) => {
219+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
217220
}
218221
ty::ConstKind::Error(_) => {
219-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
222+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
220223
}
221-
_ => {
222-
// THISPR
223-
self.eq(goal.param_env, todo!(), ty)?;
224-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
224+
ty::ConstKind::Unevaluated(uv) => {
225+
self.interner().type_of(uv.def).instantiate(self.interner(), uv.args)
225226
}
226-
}
227+
ty::ConstKind::Expr(_) => unimplemented!(
228+
"`feature(generic_const_exprs)` is not supported in the new trait solver"
229+
),
230+
ty::ConstKind::Param(_) => {
231+
unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`")
232+
}
233+
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
234+
ty::ConstKind::Value(ty, _) => ty,
235+
ty::ConstKind::Placeholder(placeholder) => {
236+
let mut candidates = goal.param_env.caller_bounds().iter().filter_map(|clause| {
237+
// `ConstArgHasType` are never desugared to be higher ranked.
238+
match clause.kind().skip_binder() {
239+
ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => {
240+
assert!(!(placeholder_ct, ty).has_escaping_bound_vars());
241+
242+
match placeholder_ct.kind() {
243+
ty::ConstKind::Placeholder(placeholder_ct)
244+
if placeholder_ct == placeholder =>
245+
{
246+
Some(ty)
247+
}
248+
_ => None,
249+
}
250+
}
251+
_ => None,
252+
}
253+
});
254+
255+
let ty = candidates.next().unwrap();
256+
assert!(candidates.next().is_none());
257+
ty
258+
}
259+
};
260+
261+
self.eq(goal.param_env, ct_ty, ty)?;
262+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
227263
}
228264
}
229265

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+22-17
Original file line numberDiff line numberDiff line change
@@ -911,23 +911,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
911911
"AliasRelate predicate should never be the predicate cause of a SelectionError"
912912
),
913913

914-
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
915-
let mut diag = self.dcx().struct_span_err(
916-
span,
917-
format!("the constant `{ct}` is not of type `{ty}`"),
918-
);
919-
self.note_type_err(
920-
&mut diag,
921-
&obligation.cause,
922-
None,
923-
None,
924-
// THISPR
925-
TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, todo!())),
926-
false,
927-
false,
928-
);
929-
diag
930-
}
914+
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => span_bug!(
915+
span,
916+
"ConstArgHasType predicate should never be the predicate cause of a SelectionError",
917+
),
931918
}
932919
}
933920

@@ -990,6 +977,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
990977
Overflow(_) => {
991978
bug!("overflow should be handled before the `report_selection_error` path");
992979
}
980+
981+
SelectionError::ConstArgHasWrongType(ct, const_ty, expected_ty) => {
982+
let mut diag = self.dcx().struct_span_err(
983+
span,
984+
format!("the constant `{ct}` is not of type `{expected_ty}`"),
985+
);
986+
987+
self.note_type_err(
988+
&mut diag,
989+
&obligation.cause,
990+
None,
991+
None,
992+
TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, const_ty)),
993+
false,
994+
false,
995+
);
996+
diag
997+
}
993998
};
994999

9951000
self.note_obligation_cause(&mut err, &obligation);

compiler/rustc_trait_selection/src/traits/fulfill.rs

+43-19
Original file line numberDiff line numberDiff line change
@@ -438,29 +438,53 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
438438
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
439439
// get unified with some const that is not of type `usize`.
440440
let ct = self.selcx.infcx.shallow_resolve_const(ct);
441-
match ct.kind() {
442-
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
441+
let ct_ty = match ct.kind() {
442+
ty::ConstKind::Infer(var) => {
443+
let var = match var {
444+
ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid),
445+
ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid),
446+
ty::InferConst::Fresh(_) => {
447+
bug!("encountered fresh const in fulfill")
448+
}
449+
};
443450
pending_obligation.stalled_on.clear();
444-
pending_obligation.stalled_on.extend([TyOrConstInferVar::Const(vid)]);
445-
ProcessResult::Unchanged
451+
pending_obligation.stalled_on.extend([var]);
452+
return ProcessResult::Unchanged;
446453
}
447454
ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]),
448-
_ => {
449-
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
450-
// Only really excercised by generic_const_exprs
451-
DefineOpaqueTypes::Yes,
452-
// THISPR
453-
todo!(),
454-
ty,
455-
) {
456-
Ok(inf_ok) => {
457-
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
458-
}
459-
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
460-
SelectionError::Unimplemented,
461-
)),
462-
}
455+
ty::ConstKind::Value(ty, _) => ty,
456+
ty::ConstKind::Unevaluated(uv) => self
457+
.selcx
458+
.infcx
459+
.tcx
460+
.type_of(uv.def)
461+
.instantiate(self.selcx.infcx.tcx, uv.args),
462+
// FIXME(generic_const_exprs): we should construct an alias like
463+
// `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing
464+
// `lhs + rhs`.
465+
ty::ConstKind::Expr(_) => {
466+
return ProcessResult::Changed(mk_pending(vec![]));
467+
}
468+
// FIXME(BoxyUwU): this doesnt seem right
469+
ty::ConstKind::Placeholder(_) => {
470+
return ProcessResult::Changed(mk_pending(vec![]));
463471
}
472+
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
473+
ty::ConstKind::Param(param_ct) => {
474+
param_ct.find_ty_from_env(obligation.param_env)
475+
}
476+
};
477+
478+
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
479+
// Only really excercised by generic_const_exprs
480+
DefineOpaqueTypes::Yes,
481+
ct_ty,
482+
ty,
483+
) {
484+
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
485+
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
486+
SelectionError::ConstArgHasWrongType(ct, ct_ty, ty),
487+
)),
464488
}
465489
}
466490

compiler/rustc_trait_selection/src/traits/select/mod.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1004,13 +1004,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10041004
// get unified with some const that is not of type `usize`.
10051005
let ct = self.infcx.shallow_resolve_const(ct);
10061006
let ct_ty = match ct.kind() {
1007-
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
1007+
ty::ConstKind::Infer(_) => {
10081008
return Ok(EvaluatedToAmbig);
10091009
}
10101010
ty::ConstKind::Error(_) => return Ok(EvaluatedToOk),
1011-
// THISPR
1012-
_ => todo!(),
1013-
// _ => ct.ty(),
1011+
ty::ConstKind::Value(ty, _) => ty,
1012+
ty::ConstKind::Unevaluated(uv) => {
1013+
self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args)
1014+
}
1015+
// FIXME(generic_const_exprs): See comment in `fulfill.rs`
1016+
ty::ConstKind::Expr(_) => return Ok(EvaluatedToOk),
1017+
// FIXME(BoxyUwU): This doesn't seem right
1018+
ty::ConstKind::Placeholder(_) => return Ok(EvaluatedToOk),
1019+
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
1020+
ty::ConstKind::Param(param_ct) => {
1021+
param_ct.find_ty_from_env(obligation.param_env)
1022+
}
10141023
};
10151024

10161025
match self.infcx.at(&obligation.cause, obligation.param_env).eq(

0 commit comments

Comments
 (0)