Skip to content

Commit 8286ea5

Browse files
committed
Move a wf-check into the site where the value is instantiated
1 parent 1481fd9 commit 8286ea5

File tree

8 files changed

+95
-59
lines changed

8 files changed

+95
-59
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
3636
use rustc_span::edition::Edition;
3737
use rustc_span::lev_distance::find_best_match_for_name;
3838
use rustc_span::symbol::{kw, Ident, Symbol};
39-
use rustc_span::Span;
39+
use rustc_span::{sym, Span};
4040
use rustc_target::spec::abi;
4141
use rustc_trait_selection::traits;
4242
use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -275,6 +275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
275275
item_segment.args(),
276276
item_segment.infer_args,
277277
None,
278+
None,
278279
);
279280
if let Some(b) = item_segment.args().bindings.first() {
280281
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -324,6 +325,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
324325
generic_args: &'a hir::GenericArgs<'_>,
325326
infer_args: bool,
326327
self_ty: Option<Ty<'tcx>>,
328+
constness: Option<ty::BoundConstness>,
327329
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
328330
// If the type is parameterized by this region, then replace this
329331
// region with the current anon region binding (in other words,
@@ -534,6 +536,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
534536
&mut substs_ctx,
535537
);
536538

539+
if let Some(ty::BoundConstness::ConstIfConst) = constness
540+
&& generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
541+
{
542+
tcx.sess.span_err(
543+
span,
544+
"~const can only be applied to `#[const_trait]` traits",
545+
);
546+
}
547+
537548
(substs, arg_count)
538549
}
539550

@@ -601,6 +612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
601612
item_segment.args(),
602613
item_segment.infer_args,
603614
None,
615+
None,
604616
);
605617

606618
if let Some(b) = item_segment.args().bindings.first() {
@@ -620,6 +632,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
620632
&self,
621633
trait_ref: &hir::TraitRef<'_>,
622634
self_ty: Ty<'tcx>,
635+
constness: ty::BoundConstness,
623636
) -> ty::TraitRef<'tcx> {
624637
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
625638

@@ -629,6 +642,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
629642
self_ty,
630643
trait_ref.path.segments.last().unwrap(),
631644
true,
645+
Some(constness),
632646
)
633647
}
634648

@@ -655,6 +669,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
655669
args,
656670
infer_args,
657671
Some(self_ty),
672+
Some(constness),
658673
);
659674

660675
let tcx = self.tcx();
@@ -680,6 +695,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
680695
speculative,
681696
&mut dup_bindings,
682697
binding_span.unwrap_or(binding.span),
698+
constness,
683699
);
684700
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
685701
}
@@ -783,13 +799,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
783799
self_ty: Ty<'tcx>,
784800
trait_segment: &hir::PathSegment<'_>,
785801
is_impl: bool,
802+
constness: Option<ty::BoundConstness>,
786803
) -> ty::TraitRef<'tcx> {
787804
let (substs, _) = self.create_substs_for_ast_trait_ref(
788805
span,
789806
trait_def_id,
790807
self_ty,
791808
trait_segment,
792809
is_impl,
810+
constness,
793811
);
794812
if let Some(b) = trait_segment.args().bindings.first() {
795813
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -805,6 +823,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
805823
self_ty: Ty<'tcx>,
806824
trait_segment: &'a hir::PathSegment<'a>,
807825
is_impl: bool,
826+
constness: Option<ty::BoundConstness>,
808827
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
809828
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
810829

@@ -816,6 +835,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
816835
trait_segment.args(),
817836
trait_segment.infer_args,
818837
Some(self_ty),
838+
constness,
819839
)
820840
}
821841

@@ -1027,6 +1047,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10271047
speculative: bool,
10281048
dup_bindings: &mut FxHashMap<DefId, Span>,
10291049
path_span: Span,
1050+
constness: ty::BoundConstness,
10301051
) -> Result<(), ErrorGuaranteed> {
10311052
// Given something like `U: SomeTrait<T = X>`, we want to produce a
10321053
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
@@ -1122,10 +1143,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11221143
trait_ref.substs,
11231144
);
11241145

1125-
debug!(
1126-
"add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
1127-
substs_trait_ref_and_assoc_item
1128-
);
1146+
debug!(?substs_trait_ref_and_assoc_item);
11291147

11301148
ty::ProjectionTy {
11311149
item_def_id: assoc_item.def_id,
@@ -1146,8 +1164,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11461164
tcx.collect_constrained_late_bound_regions(&projection_ty);
11471165
let late_bound_in_ty =
11481166
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
1149-
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
1150-
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
1167+
debug!(?late_bound_in_trait_ref);
1168+
debug!(?late_bound_in_ty);
11511169

11521170
// FIXME: point at the type params that don't have appropriate lifetimes:
11531171
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
@@ -1648,6 +1666,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16481666

16491667
// Checks that `bounds` contains exactly one element and reports appropriate
16501668
// errors otherwise.
1669+
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
16511670
fn one_bound_for_assoc_type<I>(
16521671
&self,
16531672
all_candidates: impl Fn() -> I,
@@ -1677,10 +1696,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16771696
return Err(reported);
16781697
}
16791698
};
1680-
debug!("one_bound_for_assoc_type: bound = {:?}", bound);
1699+
debug!(?bound);
16811700

16821701
if let Some(bound2) = next_cand {
1683-
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
1702+
debug!(?bound2);
16841703

16851704
let is_equality = is_equality();
16861705
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
@@ -1776,6 +1795,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17761795
// parameter or `Self`.
17771796
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
17781797
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
1798+
#[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
17791799
pub fn associated_path_to_ty(
17801800
&self,
17811801
hir_ref_id: hir::HirId,
@@ -1793,8 +1813,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17931813
Res::Err
17941814
};
17951815

1796-
debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
1797-
17981816
// Check if we have an enum variant.
17991817
let mut variant_resolution = None;
18001818
if let ty::Adt(adt_def, _) = qself_ty.kind() {
@@ -2050,6 +2068,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20502068
item_def_id: DefId,
20512069
trait_segment: &hir::PathSegment<'_>,
20522070
item_segment: &hir::PathSegment<'_>,
2071+
constness: ty::BoundConstness,
20532072
) -> Ty<'tcx> {
20542073
let tcx = self.tcx();
20552074

@@ -2094,8 +2113,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20942113

20952114
debug!("qpath_to_ty: self_type={:?}", self_ty);
20962115

2097-
let trait_ref =
2098-
self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
2116+
let trait_ref = self.ast_path_to_mono_trait_ref(
2117+
span,
2118+
trait_def_id,
2119+
self_ty,
2120+
trait_segment,
2121+
false,
2122+
Some(constness),
2123+
);
20992124

21002125
let item_substs = self.create_substs_for_associated_item(
21012126
span,
@@ -2534,12 +2559,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
25342559
Res::Def(DefKind::AssocTy, def_id) => {
25352560
debug_assert!(path.segments.len() >= 2);
25362561
self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
2562+
// HACK: until we support `<Type as ~const Trait>`, assume all of them are.
2563+
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
2564+
ty::BoundConstness::ConstIfConst
2565+
} else {
2566+
ty::BoundConstness::NotConst
2567+
};
25372568
self.qpath_to_ty(
25382569
span,
25392570
opt_self_ty,
25402571
def_id,
25412572
&path.segments[path.segments.len() - 2],
25422573
path.segments.last().unwrap(),
2574+
constness,
25432575
)
25442576
}
25452577
Res::PrimTy(prim_ty) => {
@@ -2658,6 +2690,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
26582690
&GenericArgs::none(),
26592691
true,
26602692
None,
2693+
None,
26612694
);
26622695
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
26632696
.subst(tcx, substs)
@@ -2766,6 +2799,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27662799
}
27672800
}
27682801

2802+
#[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
27692803
pub fn ty_of_fn(
27702804
&self,
27712805
hir_id: hir::HirId,
@@ -2775,8 +2809,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27752809
generics: Option<&hir::Generics<'_>>,
27762810
hir_ty: Option<&hir::Ty<'_>>,
27772811
) -> ty::PolyFnSig<'tcx> {
2778-
debug!("ty_of_fn");
2779-
27802812
let tcx = self.tcx();
27812813
let bound_vars = tcx.late_bound_vars(hir_id);
27822814
debug!(?bound_vars);
@@ -2826,7 +2858,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
28262858
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
28272859
};
28282860

2829-
debug!("ty_of_fn: output_ty={:?}", output_ty);
2861+
debug!(?output_ty);
28302862

28312863
let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
28322864
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
@@ -2903,8 +2935,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29032935
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
29042936
hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
29052937

2906-
let trait_ref =
2907-
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
2938+
let trait_ref = self.instantiate_mono_trait_ref(
2939+
i.of_trait.as_ref()?,
2940+
self.ast_ty_to_ty(i.self_ty),
2941+
ty::BoundConstness::NotConst,
2942+
);
29082943

29092944
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
29102945
tcx,

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
11431143
}
11441144

11451145
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
1146-
// Do not try to inference the return type for a impl method coming from a trait
1146+
// Do not try to infer the return type for a impl method coming from a trait
11471147
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
11481148
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
11491149
&& i.of_trait.is_some()
@@ -1286,10 +1286,37 @@ fn infer_return_ty_for_fn_sig<'tcx>(
12861286

12871287
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
12881288
let icx = ItemCtxt::new(tcx, def_id);
1289-
match tcx.hir().expect_item(def_id.expect_local()).kind {
1289+
let item = tcx.hir().expect_item(def_id.expect_local());
1290+
match item.kind {
12901291
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
12911292
let selfty = tcx.type_of(def_id);
1292-
<dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
1293+
<dyn AstConv<'_>>::instantiate_mono_trait_ref(
1294+
&icx,
1295+
ast_trait_ref,
1296+
selfty,
1297+
match impl_.constness {
1298+
hir::Constness::Const => {
1299+
if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
1300+
let trait_name = tcx.item_name(trait_def_id);
1301+
let mut err = tcx.sess.struct_span_err(
1302+
ast_trait_ref.path.span,
1303+
&format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"),
1304+
);
1305+
if trait_def_id.is_local() {
1306+
let sp = tcx.def_span(trait_def_id).shrink_to_lo();
1307+
err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable);
1308+
}
1309+
err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`");
1310+
err.note("adding a non-const method body in the future would be a breaking change");
1311+
err.emit();
1312+
ty::BoundConstness::NotConst
1313+
} else {
1314+
ty::BoundConstness::ConstIfConst
1315+
}
1316+
},
1317+
hir::Constness::NotConst => ty::BoundConstness::NotConst,
1318+
},
1319+
)
12931320
}),
12941321
_ => bug!(),
12951322
}

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -303,32 +303,6 @@ impl<'tcx> WfPredicates<'tcx> {
303303
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
304304
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
305305
} else {
306-
if !tcx.has_attr(trait_ref.def_id, rustc_span::sym::const_trait) {
307-
if let Some(item) = self.item &&
308-
let hir::ItemKind::Impl(impl_) = item.kind &&
309-
let Some(trait_) = &impl_.of_trait &&
310-
let Some(def_id) = trait_.trait_def_id() &&
311-
def_id == trait_ref.def_id
312-
{
313-
let trait_name = tcx.item_name(def_id);
314-
let mut err = tcx.sess.struct_span_err(
315-
self.span,
316-
&format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"),
317-
);
318-
if def_id.is_local() {
319-
let sp = tcx.def_span(def_id).shrink_to_lo();
320-
err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable);
321-
}
322-
err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`");
323-
err.note("adding a non-const method body in the future would be a breaking change");
324-
err.emit();
325-
} else {
326-
tcx.sess.span_err(
327-
self.span,
328-
"~const can only be applied to `#[const_trait]` traits",
329-
);
330-
}
331-
}
332306
self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
333307
};
334308

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: ~const can only be applied to `#[const_trait]` traits
2-
--> $DIR/super-traits-fail-2.rs:11:12
2+
--> $DIR/super-traits-fail-2.rs:11:19
33
|
44
LL | trait Bar: ~const Foo {}
5-
| ^^^^^^^^^^
5+
| ^^^
66

77
error: aborting due to previous error
88

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: ~const can only be applied to `#[const_trait]` traits
2-
--> $DIR/super-traits-fail-2.rs:11:12
2+
--> $DIR/super-traits-fail-2.rs:11:19
33
|
44
LL | trait Bar: ~const Foo {}
5-
| ^^^^^^^^^^
5+
| ^^^
66

77
error: aborting due to previous error
88

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
error: ~const can only be applied to `#[const_trait]` traits
2-
--> $DIR/super-traits-fail-3.rs:12:12
2+
--> $DIR/super-traits-fail-3.rs:12:19
33
|
44
LL | trait Bar: ~const Foo {}
5-
| ^^^^^^^^^^
5+
| ^^^
66

77
error: ~const can only be applied to `#[const_trait]` traits
8-
--> $DIR/super-traits-fail-3.rs:15:17
8+
--> $DIR/super-traits-fail-3.rs:15:24
99
|
1010
LL | const fn foo<T: ~const Bar>(x: &T) {
11-
| ^^^^^^^^^^
11+
| ^^^
1212

1313
error: aborting due to 2 previous errors
1414

0 commit comments

Comments
 (0)