Rollup merge of #103525 - oli-obk:const_impl_on_non_const_trait, r=lcnr
Move a wf-check into the site where the value is instantiated r? ``@lcnr``
This commit is contained in:
commit
2bd49c34e5
@ -137,3 +137,12 @@ hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(l
|
|||||||
hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
|
hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
|
||||||
|
|
||||||
hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
|
hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
|
||||||
|
|
||||||
|
hir_analysis_const_impl_for_non_const_trait =
|
||||||
|
const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
|
||||||
|
.suggestion = mark `{$trait_name}` as const
|
||||||
|
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
|
||||||
|
.adding = adding a non-const method body in the future would be a breaking change
|
||||||
|
|
||||||
|
hir_analysis_const_bound_for_non_const_trait =
|
||||||
|
~const can only be applied to `#[const_trait]` traits
|
||||||
|
@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
|
|||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::{sym, Span};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
||||||
@ -275,6 +275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
item_segment.args(),
|
item_segment.args(),
|
||||||
item_segment.infer_args,
|
item_segment.infer_args,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
if let Some(b) = item_segment.args().bindings.first() {
|
if let Some(b) = item_segment.args().bindings.first() {
|
||||||
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||||
@ -324,6 +325,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
generic_args: &'a hir::GenericArgs<'_>,
|
generic_args: &'a hir::GenericArgs<'_>,
|
||||||
infer_args: bool,
|
infer_args: bool,
|
||||||
self_ty: Option<Ty<'tcx>>,
|
self_ty: Option<Ty<'tcx>>,
|
||||||
|
constness: Option<ty::BoundConstness>,
|
||||||
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
|
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
|
||||||
// If the type is parameterized by this region, then replace this
|
// If the type is parameterized by this region, then replace this
|
||||||
// region with the current anon region binding (in other words,
|
// region with the current anon region binding (in other words,
|
||||||
@ -534,6 +536,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
&mut substs_ctx,
|
&mut substs_ctx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(ty::BoundConstness::ConstIfConst) = constness
|
||||||
|
&& generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
|
||||||
|
{
|
||||||
|
tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
|
||||||
|
}
|
||||||
|
|
||||||
(substs, arg_count)
|
(substs, arg_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,6 +609,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
item_segment.args(),
|
item_segment.args(),
|
||||||
item_segment.infer_args,
|
item_segment.infer_args,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(b) = item_segment.args().bindings.first() {
|
if let Some(b) = item_segment.args().bindings.first() {
|
||||||
@ -620,6 +629,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
&self,
|
&self,
|
||||||
trait_ref: &hir::TraitRef<'_>,
|
trait_ref: &hir::TraitRef<'_>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
constness: ty::BoundConstness,
|
||||||
) -> ty::TraitRef<'tcx> {
|
) -> ty::TraitRef<'tcx> {
|
||||||
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
|
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
|
||||||
|
|
||||||
@ -629,6 +639,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
self_ty,
|
self_ty,
|
||||||
trait_ref.path.segments.last().unwrap(),
|
trait_ref.path.segments.last().unwrap(),
|
||||||
true,
|
true,
|
||||||
|
Some(constness),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,6 +666,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
args,
|
args,
|
||||||
infer_args,
|
infer_args,
|
||||||
Some(self_ty),
|
Some(self_ty),
|
||||||
|
Some(constness),
|
||||||
);
|
);
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
@ -680,6 +692,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
speculative,
|
speculative,
|
||||||
&mut dup_bindings,
|
&mut dup_bindings,
|
||||||
binding_span.unwrap_or(binding.span),
|
binding_span.unwrap_or(binding.span),
|
||||||
|
constness,
|
||||||
);
|
);
|
||||||
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
|
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
|
||||||
}
|
}
|
||||||
@ -783,6 +796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
trait_segment: &hir::PathSegment<'_>,
|
trait_segment: &hir::PathSegment<'_>,
|
||||||
is_impl: bool,
|
is_impl: bool,
|
||||||
|
constness: Option<ty::BoundConstness>,
|
||||||
) -> ty::TraitRef<'tcx> {
|
) -> ty::TraitRef<'tcx> {
|
||||||
let (substs, _) = self.create_substs_for_ast_trait_ref(
|
let (substs, _) = self.create_substs_for_ast_trait_ref(
|
||||||
span,
|
span,
|
||||||
@ -790,6 +804,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
self_ty,
|
self_ty,
|
||||||
trait_segment,
|
trait_segment,
|
||||||
is_impl,
|
is_impl,
|
||||||
|
constness,
|
||||||
);
|
);
|
||||||
if let Some(b) = trait_segment.args().bindings.first() {
|
if let Some(b) = trait_segment.args().bindings.first() {
|
||||||
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
|
||||||
@ -805,6 +820,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
trait_segment: &'a hir::PathSegment<'a>,
|
trait_segment: &'a hir::PathSegment<'a>,
|
||||||
is_impl: bool,
|
is_impl: bool,
|
||||||
|
constness: Option<ty::BoundConstness>,
|
||||||
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
|
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
|
||||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
||||||
|
|
||||||
@ -816,6 +832,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
trait_segment.args(),
|
trait_segment.args(),
|
||||||
trait_segment.infer_args,
|
trait_segment.infer_args,
|
||||||
Some(self_ty),
|
Some(self_ty),
|
||||||
|
constness,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,6 +1044,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
speculative: bool,
|
speculative: bool,
|
||||||
dup_bindings: &mut FxHashMap<DefId, Span>,
|
dup_bindings: &mut FxHashMap<DefId, Span>,
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
|
constness: ty::BoundConstness,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
// Given something like `U: SomeTrait<T = X>`, we want to produce a
|
// Given something like `U: SomeTrait<T = X>`, we want to produce a
|
||||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||||
@ -1122,10 +1140,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
trait_ref.substs,
|
trait_ref.substs,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug!(
|
debug!(?substs_trait_ref_and_assoc_item);
|
||||||
"add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
|
|
||||||
substs_trait_ref_and_assoc_item
|
|
||||||
);
|
|
||||||
|
|
||||||
ty::ProjectionTy {
|
ty::ProjectionTy {
|
||||||
item_def_id: assoc_item.def_id,
|
item_def_id: assoc_item.def_id,
|
||||||
@ -1146,8 +1161,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
||||||
let late_bound_in_ty =
|
let late_bound_in_ty =
|
||||||
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
|
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
|
||||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
debug!(?late_bound_in_trait_ref);
|
||||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
debug!(?late_bound_in_ty);
|
||||||
|
|
||||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||||
@ -1648,6 +1663,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
// Checks that `bounds` contains exactly one element and reports appropriate
|
// Checks that `bounds` contains exactly one element and reports appropriate
|
||||||
// errors otherwise.
|
// errors otherwise.
|
||||||
|
#[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
|
||||||
fn one_bound_for_assoc_type<I>(
|
fn one_bound_for_assoc_type<I>(
|
||||||
&self,
|
&self,
|
||||||
all_candidates: impl Fn() -> I,
|
all_candidates: impl Fn() -> I,
|
||||||
@ -1677,10 +1693,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
return Err(reported);
|
return Err(reported);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!("one_bound_for_assoc_type: bound = {:?}", bound);
|
debug!(?bound);
|
||||||
|
|
||||||
if let Some(bound2) = next_cand {
|
if let Some(bound2) = next_cand {
|
||||||
debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
|
debug!(?bound2);
|
||||||
|
|
||||||
let is_equality = is_equality();
|
let is_equality = is_equality();
|
||||||
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
|
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
|
||||||
@ -1776,6 +1792,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
// parameter or `Self`.
|
// parameter or `Self`.
|
||||||
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
|
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
|
||||||
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
|
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
|
||||||
|
#[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
|
||||||
pub fn associated_path_to_ty(
|
pub fn associated_path_to_ty(
|
||||||
&self,
|
&self,
|
||||||
hir_ref_id: hir::HirId,
|
hir_ref_id: hir::HirId,
|
||||||
@ -1793,8 +1810,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
Res::Err
|
Res::Err
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
|
|
||||||
|
|
||||||
// Check if we have an enum variant.
|
// Check if we have an enum variant.
|
||||||
let mut variant_resolution = None;
|
let mut variant_resolution = None;
|
||||||
if let ty::Adt(adt_def, _) = qself_ty.kind() {
|
if let ty::Adt(adt_def, _) = qself_ty.kind() {
|
||||||
@ -2050,6 +2065,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
item_def_id: DefId,
|
item_def_id: DefId,
|
||||||
trait_segment: &hir::PathSegment<'_>,
|
trait_segment: &hir::PathSegment<'_>,
|
||||||
item_segment: &hir::PathSegment<'_>,
|
item_segment: &hir::PathSegment<'_>,
|
||||||
|
constness: ty::BoundConstness,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
@ -2094,8 +2110,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
debug!("qpath_to_ty: self_type={:?}", self_ty);
|
debug!("qpath_to_ty: self_type={:?}", self_ty);
|
||||||
|
|
||||||
let trait_ref =
|
let trait_ref = self.ast_path_to_mono_trait_ref(
|
||||||
self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
|
span,
|
||||||
|
trait_def_id,
|
||||||
|
self_ty,
|
||||||
|
trait_segment,
|
||||||
|
false,
|
||||||
|
Some(constness),
|
||||||
|
);
|
||||||
|
|
||||||
let item_substs = self.create_substs_for_associated_item(
|
let item_substs = self.create_substs_for_associated_item(
|
||||||
span,
|
span,
|
||||||
@ -2534,12 +2556,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
Res::Def(DefKind::AssocTy, def_id) => {
|
Res::Def(DefKind::AssocTy, def_id) => {
|
||||||
debug_assert!(path.segments.len() >= 2);
|
debug_assert!(path.segments.len() >= 2);
|
||||||
self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
|
self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
|
||||||
|
// HACK: until we support `<Type as ~const Trait>`, assume all of them are.
|
||||||
|
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
|
||||||
|
ty::BoundConstness::ConstIfConst
|
||||||
|
} else {
|
||||||
|
ty::BoundConstness::NotConst
|
||||||
|
};
|
||||||
self.qpath_to_ty(
|
self.qpath_to_ty(
|
||||||
span,
|
span,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
def_id,
|
def_id,
|
||||||
&path.segments[path.segments.len() - 2],
|
&path.segments[path.segments.len() - 2],
|
||||||
path.segments.last().unwrap(),
|
path.segments.last().unwrap(),
|
||||||
|
constness,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Res::PrimTy(prim_ty) => {
|
Res::PrimTy(prim_ty) => {
|
||||||
@ -2658,6 +2687,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
&GenericArgs::none(),
|
&GenericArgs::none(),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
|
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
|
||||||
.subst(tcx, substs)
|
.subst(tcx, substs)
|
||||||
@ -2766,6 +2796,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
|
||||||
pub fn ty_of_fn(
|
pub fn ty_of_fn(
|
||||||
&self,
|
&self,
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
@ -2775,8 +2806,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
generics: Option<&hir::Generics<'_>>,
|
generics: Option<&hir::Generics<'_>>,
|
||||||
hir_ty: Option<&hir::Ty<'_>>,
|
hir_ty: Option<&hir::Ty<'_>>,
|
||||||
) -> ty::PolyFnSig<'tcx> {
|
) -> ty::PolyFnSig<'tcx> {
|
||||||
debug!("ty_of_fn");
|
|
||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let bound_vars = tcx.late_bound_vars(hir_id);
|
let bound_vars = tcx.late_bound_vars(hir_id);
|
||||||
debug!(?bound_vars);
|
debug!(?bound_vars);
|
||||||
@ -2826,7 +2855,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
|
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("ty_of_fn: output_ty={:?}", output_ty);
|
debug!(?output_ty);
|
||||||
|
|
||||||
let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
|
let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
|
||||||
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
|
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
|
||||||
@ -2903,8 +2932,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
|
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
|
||||||
hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
|
hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
|
||||||
|
|
||||||
let trait_ref =
|
let trait_ref = self.instantiate_mono_trait_ref(
|
||||||
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
|
i.of_trait.as_ref()?,
|
||||||
|
self.ast_ty_to_ty(i.self_ty),
|
||||||
|
ty::BoundConstness::NotConst,
|
||||||
|
);
|
||||||
|
|
||||||
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
|
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -1143,7 +1143,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
|
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
|
||||||
// Do not try to inference the return type for a impl method coming from a trait
|
// Do not try to infer the return type for a impl method coming from a trait
|
||||||
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
|
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
|
||||||
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
|
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
|
||||||
&& i.of_trait.is_some()
|
&& i.of_trait.is_some()
|
||||||
@ -1286,15 +1286,46 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
|||||||
|
|
||||||
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
|
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
|
||||||
let icx = ItemCtxt::new(tcx, def_id);
|
let icx = ItemCtxt::new(tcx, def_id);
|
||||||
match tcx.hir().expect_item(def_id.expect_local()).kind {
|
let item = tcx.hir().expect_item(def_id.expect_local());
|
||||||
|
match item.kind {
|
||||||
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
|
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
|
||||||
let selfty = tcx.type_of(def_id);
|
let selfty = tcx.type_of(def_id);
|
||||||
<dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
|
<dyn AstConv<'_>>::instantiate_mono_trait_ref(
|
||||||
|
&icx,
|
||||||
|
ast_trait_ref,
|
||||||
|
selfty,
|
||||||
|
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_impl_constness(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
constness: hir::Constness,
|
||||||
|
ast_trait_ref: &hir::TraitRef<'_>,
|
||||||
|
) -> ty::BoundConstness {
|
||||||
|
match constness {
|
||||||
|
hir::Constness::Const => {
|
||||||
|
if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
|
||||||
|
let trait_name = tcx.item_name(trait_def_id).to_string();
|
||||||
|
tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
|
||||||
|
trait_ref_span: ast_trait_ref.path.span,
|
||||||
|
trait_name,
|
||||||
|
local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
|
||||||
|
marking: (),
|
||||||
|
adding: (),
|
||||||
|
});
|
||||||
|
ty::BoundConstness::NotConst
|
||||||
|
} else {
|
||||||
|
ty::BoundConstness::ConstIfConst
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hir::Constness::NotConst => ty::BoundConstness::NotConst,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
|
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
|
||||||
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
|
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
|
||||||
let item = tcx.hir().expect_item(def_id.expect_local());
|
let item = tcx.hir().expect_item(def_id.expect_local());
|
||||||
|
@ -249,3 +249,24 @@ pub struct ExpectedUsedSymbol {
|
|||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_const_impl_for_non_const_trait)]
|
||||||
|
pub struct ConstImplForNonConstTrait {
|
||||||
|
#[primary_span]
|
||||||
|
pub trait_ref_span: Span,
|
||||||
|
pub trait_name: String,
|
||||||
|
#[suggestion(applicability = "machine-applicable", code = "#[const_trait]")]
|
||||||
|
pub local_trait_span: Option<Span>,
|
||||||
|
#[note]
|
||||||
|
pub marking: (),
|
||||||
|
#[note(adding)]
|
||||||
|
pub adding: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_const_bound_for_non_const_trait)]
|
||||||
|
pub struct ConstBoundForNonConstTrait {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
@ -303,32 +303,6 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
|
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
|
||||||
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
|
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
|
||||||
} else {
|
} else {
|
||||||
if !tcx.has_attr(trait_ref.def_id, rustc_span::sym::const_trait) {
|
|
||||||
if let Some(item) = self.item &&
|
|
||||||
let hir::ItemKind::Impl(impl_) = item.kind &&
|
|
||||||
let Some(trait_) = &impl_.of_trait &&
|
|
||||||
let Some(def_id) = trait_.trait_def_id() &&
|
|
||||||
def_id == trait_ref.def_id
|
|
||||||
{
|
|
||||||
let trait_name = tcx.item_name(def_id);
|
|
||||||
let mut err = tcx.sess.struct_span_err(
|
|
||||||
self.span,
|
|
||||||
&format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"),
|
|
||||||
);
|
|
||||||
if def_id.is_local() {
|
|
||||||
let sp = tcx.def_span(def_id).shrink_to_lo();
|
|
||||||
err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable);
|
|
||||||
}
|
|
||||||
err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`");
|
|
||||||
err.note("adding a non-const method body in the future would be a breaking change");
|
|
||||||
err.emit();
|
|
||||||
} else {
|
|
||||||
tcx.sess.span_err(
|
|
||||||
self.span,
|
|
||||||
"~const can only be applied to `#[const_trait]` traits",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
|
self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: ~const can only be applied to `#[const_trait]` traits
|
error: ~const can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/super-traits-fail-2.rs:11:12
|
--> $DIR/super-traits-fail-2.rs:11:19
|
||||||
|
|
|
|
||||||
LL | trait Bar: ~const Foo {}
|
LL | trait Bar: ~const Foo {}
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: ~const can only be applied to `#[const_trait]` traits
|
error: ~const can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/super-traits-fail-2.rs:11:12
|
--> $DIR/super-traits-fail-2.rs:11:19
|
||||||
|
|
|
|
||||||
LL | trait Bar: ~const Foo {}
|
LL | trait Bar: ~const Foo {}
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
error: ~const can only be applied to `#[const_trait]` traits
|
error: ~const can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/super-traits-fail-3.rs:12:12
|
--> $DIR/super-traits-fail-3.rs:12:19
|
||||||
|
|
|
|
||||||
LL | trait Bar: ~const Foo {}
|
LL | trait Bar: ~const Foo {}
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: ~const can only be applied to `#[const_trait]` traits
|
error: ~const can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/super-traits-fail-3.rs:15:17
|
--> $DIR/super-traits-fail-3.rs:15:24
|
||||||
|
|
|
|
||||||
LL | const fn foo<T: ~const Bar>(x: &T) {
|
LL | const fn foo<T: ~const Bar>(x: &T) {
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: ~const can only be applied to `#[const_trait]` traits
|
error: ~const can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/super-traits-fail-3.rs:12:12
|
--> $DIR/super-traits-fail-3.rs:12:19
|
||||||
|
|
|
|
||||||
LL | trait Bar: ~const Foo {}
|
LL | trait Bar: ~const Foo {}
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: ~const can only be applied to `#[const_trait]` traits
|
error: ~const can only be applied to `#[const_trait]` traits
|
||||||
--> $DIR/super-traits-fail-3.rs:15:17
|
--> $DIR/super-traits-fail-3.rs:15:24
|
||||||
|
|
|
|
||||||
LL | const fn foo<T: ~const Bar>(x: &T) {
|
LL | const fn foo<T: ~const Bar>(x: &T) {
|
||||||
| ^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user