Skip to content

Commit 2c4a8fc

Browse files
committed
Fully implement ConstArgHasType
1 parent 34f1707 commit 2c4a8fc

File tree

7 files changed

+158
-103
lines changed

7 files changed

+158
-103
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 { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> },
619621
}
620622

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

compiler/rustc_middle/src/ty/mod.rs

+24
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,30 @@ pub struct Placeholder<T> {
934934
pub universe: UniverseIndex,
935935
pub bound: T,
936936
}
937+
impl Placeholder<BoundVar> {
938+
pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> {
939+
let mut candidates = env.caller_bounds().iter().filter_map(|clause| {
940+
// `ConstArgHasType` are never desugared to be higher ranked.
941+
match clause.kind().skip_binder() {
942+
ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => {
943+
assert!(!(placeholder_ct, ty).has_escaping_bound_vars());
944+
945+
match placeholder_ct.kind() {
946+
ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => {
947+
Some(ty)
948+
}
949+
_ => None,
950+
}
951+
}
952+
_ => None,
953+
}
954+
});
955+
956+
let ty = candidates.next().unwrap();
957+
assert!(candidates.next().is_none());
958+
ty
959+
}
960+
}
937961

938962
pub type PlaceholderRegion = Placeholder<BoundRegion>;
939963

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

+24-17
Original file line numberDiff line numberDiff line change
@@ -200,30 +200,37 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
200200
) -> QueryResult<'tcx> {
201201
let (ct, ty) = goal.predicate;
202202

203-
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
204-
// other than `ConstKind::Value`. Unfortunately this would require looking in the
205-
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
206-
// have not yet gotten around to implementing this though.
207-
//
208-
// We do still stall on infer vars though as otherwise a goal like:
209-
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
210-
// get unified with some const that is not of type `usize`.
211-
match ct.kind() {
203+
let ct_ty = match ct.kind() {
212204
// FIXME: Ignore effect vars because canonicalization doesn't handle them correctly
213205
// and if we stall on the var then we wind up creating ambiguity errors in a probe
214206
// 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)
207+
ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => {
208+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
209+
}
210+
ty::ConstKind::Infer(_) => {
211+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
217212
}
218213
ty::ConstKind::Error(_) => {
219-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
214+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
220215
}
221-
_ => {
222-
// THISPR
223-
self.eq(goal.param_env, todo!(), ty)?;
224-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
216+
ty::ConstKind::Unevaluated(uv) => {
217+
self.interner().type_of(uv.def).instantiate(self.interner(), uv.args)
225218
}
226-
}
219+
ty::ConstKind::Expr(_) => unimplemented!(
220+
"`feature(generic_const_exprs)` is not supported in the new trait solver"
221+
),
222+
ty::ConstKind::Param(_) => {
223+
unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`")
224+
}
225+
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
226+
ty::ConstKind::Value(ty, _) => ty,
227+
ty::ConstKind::Placeholder(placeholder) => {
228+
placeholder.find_const_ty_from_env(goal.param_env)
229+
}
230+
};
231+
232+
self.eq(goal.param_env, ct_ty, ty)?;
233+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
227234
}
228235
}
229236

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

+32-46
Original file line numberDiff line numberDiff line change
@@ -876,57 +876,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
876876
}
877877
}
878878

879-
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
880-
// Errors for `ConstEvaluatable` predicates show up as
881-
// `SelectionError::ConstEvalFailure`,
882-
// not `Unimplemented`.
879+
// Errors for `ConstEvaluatable` predicates show up as
880+
// `SelectionError::ConstEvalFailure`,
881+
// not `Unimplemented`.
882+
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
883+
// Errors for `ConstEquate` predicates show up as
884+
// `SelectionError::ConstEvalFailure`,
885+
// not `Unimplemented`.
886+
| ty::PredicateKind::ConstEquate { .. }
887+
// Ambiguous predicates should never error
888+
| ty::PredicateKind::Ambiguous
889+
| ty::PredicateKind::NormalizesTo { .. }
890+
| ty::PredicateKind::AliasRelate { .. }
891+
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {
883892
span_bug!(
884893
span,
885-
"const-evaluatable requirement gave wrong error: `{:?}`",
894+
"Unexpected `Predicate` for `SelectionError`: `{:?}`",
886895
obligation
887896
)
888897
}
889-
890-
ty::PredicateKind::ConstEquate(..) => {
891-
// Errors for `ConstEquate` predicates show up as
892-
// `SelectionError::ConstEvalFailure`,
893-
// not `Unimplemented`.
894-
span_bug!(
895-
span,
896-
"const-equate requirement gave wrong error: `{:?}`",
897-
obligation
898-
)
899-
}
900-
901-
ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
902-
903-
ty::PredicateKind::NormalizesTo(..) => span_bug!(
904-
span,
905-
"NormalizesTo predicate should never be the predicate cause of a SelectionError"
906-
),
907-
908-
ty::PredicateKind::AliasRelate(..) => span_bug!(
909-
span,
910-
"AliasRelate predicate should never be the predicate cause of a SelectionError"
911-
),
912-
913-
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
914-
let mut diag = self.dcx().struct_span_err(
915-
span,
916-
format!("the constant `{ct}` is not of type `{ty}`"),
917-
);
918-
self.note_type_err(
919-
&mut diag,
920-
&obligation.cause,
921-
None,
922-
None,
923-
// THISPR
924-
TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, todo!())),
925-
false,
926-
false,
927-
);
928-
diag
929-
}
930898
}
931899
}
932900

@@ -989,6 +957,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
989957
Overflow(_) => {
990958
bug!("overflow should be handled before the `report_selection_error` path");
991959
}
960+
961+
SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => {
962+
let mut diag = self.dcx().struct_span_err(
963+
span,
964+
format!("the constant `{ct}` is not of type `{expected_ty}`"),
965+
);
966+
967+
self.note_type_err(
968+
&mut diag,
969+
&obligation.cause,
970+
None,
971+
None,
972+
TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, ct_ty)),
973+
false,
974+
false,
975+
);
976+
diag
977+
}
992978
};
993979

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

compiler/rustc_trait_selection/src/traits/fulfill.rs

+40-28
Original file line numberDiff line numberDiff line change
@@ -439,38 +439,50 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
439439
// This is because this is not ever a useful obligation to report
440440
// as the cause of an overflow.
441441
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
442-
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
443-
// other than `ConstKind::Value`. Unfortunately this would require looking in the
444-
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
445-
// don't really want to implement this in the old solver so I haven't.
446-
//
447-
// We do still stall on infer vars though as otherwise a goal like:
448-
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
449-
// get unified with some const that is not of type `usize`.
450-
let ct = self.selcx.infcx.shallow_resolve_const(ct);
451-
match ct.kind() {
452-
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
442+
let ct = infcx.shallow_resolve_const(ct);
443+
let ct_ty = match ct.kind() {
444+
ty::ConstKind::Infer(var) => {
445+
let var = match var {
446+
ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid),
447+
ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid),
448+
ty::InferConst::Fresh(_) => {
449+
bug!("encountered fresh const in fulfill")
450+
}
451+
};
453452
pending_obligation.stalled_on.clear();
454-
pending_obligation.stalled_on.extend([TyOrConstInferVar::Const(vid)]);
455-
ProcessResult::Unchanged
453+
pending_obligation.stalled_on.extend([var]);
454+
return ProcessResult::Unchanged;
456455
}
457456
ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]),
458-
_ => {
459-
match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq(
460-
// Only really excercised by generic_const_exprs
461-
DefineOpaqueTypes::Yes,
462-
// THISPR
463-
todo!(),
464-
ty,
465-
) {
466-
Ok(inf_ok) => {
467-
ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
468-
}
469-
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
470-
SelectionError::Unimplemented,
471-
)),
472-
}
457+
ty::ConstKind::Value(ty, _) => ty,
458+
ty::ConstKind::Unevaluated(uv) => {
459+
infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
460+
}
461+
// FIXME(generic_const_exprs): we should construct an alias like
462+
// `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing
463+
// `lhs + rhs`.
464+
ty::ConstKind::Expr(_) => {
465+
return ProcessResult::Changed(mk_pending(vec![]));
466+
}
467+
ty::ConstKind::Placeholder(_) => {
468+
bug!("placeholder const {:?} in old solver", ct)
469+
}
470+
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
471+
ty::ConstKind::Param(param_ct) => {
472+
param_ct.find_ty_from_env(obligation.param_env)
473473
}
474+
};
475+
476+
match infcx.at(&obligation.cause, obligation.param_env).eq(
477+
// Only really excercised by generic_const_exprs
478+
DefineOpaqueTypes::Yes,
479+
ct_ty,
480+
ty,
481+
) {
482+
Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
483+
Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
484+
SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty: ty },
485+
)),
474486
}
475487
}
476488

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

+14-12
Original file line numberDiff line numberDiff line change
@@ -994,23 +994,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
994994
}
995995
ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
996996
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
997-
// FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant
998-
// other than `ConstKind::Value`. Unfortunately this would require looking in the
999-
// env for any `ConstArgHasType` assumptions for parameters and placeholders. I
1000-
// don't really want to implement this in the old solver so I haven't.
1001-
//
1002-
// We do still stall on infer vars though as otherwise a goal like:
1003-
// `ConstArgHasType(?x: usize, usize)` can succeed even though it might later
1004-
// get unified with some const that is not of type `usize`.
1005997
let ct = self.infcx.shallow_resolve_const(ct);
1006998
let ct_ty = match ct.kind() {
1007-
ty::ConstKind::Infer(ty::InferConst::Var(_)) => {
999+
ty::ConstKind::Infer(_) => {
10081000
return Ok(EvaluatedToAmbig);
10091001
}
10101002
ty::ConstKind::Error(_) => return Ok(EvaluatedToOk),
1011-
// THISPR
1012-
_ => todo!(),
1013-
// _ => ct.ty(),
1003+
ty::ConstKind::Value(ty, _) => ty,
1004+
ty::ConstKind::Unevaluated(uv) => {
1005+
self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args)
1006+
}
1007+
// FIXME(generic_const_exprs): See comment in `fulfill.rs`
1008+
ty::ConstKind::Expr(_) => return Ok(EvaluatedToOk),
1009+
ty::ConstKind::Placeholder(_) => {
1010+
bug!("placeholder const {:?} in old solver", ct)
1011+
}
1012+
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
1013+
ty::ConstKind::Param(param_ct) => {
1014+
param_ct.find_ty_from_env(obligation.param_env)
1015+
}
10141016
};
10151017

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

0 commit comments

Comments
 (0)