Merge from rustc
This commit is contained in:
41
Cargo.lock
41
Cargo.lock
@@ -3495,25 +3495,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rls-data"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a58135eb039f3a3279a33779192f0ee78b56f57ae636e25cec83530e41debb99"
|
||||
dependencies = [
|
||||
"rls-span",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rls-span"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0eea58478fc06e15f71b03236612173a1b81e9770314edecfa664375e3e4c86"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-demangler"
|
||||
version = "0.0.1"
|
||||
@@ -3965,7 +3946,6 @@ dependencies = [
|
||||
"rustc_middle",
|
||||
"rustc_parse",
|
||||
"rustc_plugin_impl",
|
||||
"rustc_save_analysis",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
@@ -4625,27 +4605,6 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_save_analysis"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rls-data",
|
||||
"rls-span",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_serialize"
|
||||
version = "0.0.0"
|
||||
|
||||
@@ -139,13 +139,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Cast(expr, ty)
|
||||
}
|
||||
ExprKind::Type(expr, ty) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
|
||||
hir::ExprKind::Type(expr, ty)
|
||||
}
|
||||
ExprKind::AddrOf(k, m, ohs) => {
|
||||
|
||||
@@ -378,8 +378,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
)
|
||||
});
|
||||
|
||||
let lowered_ty = this
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let lowered_ty = this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
|
||||
);
|
||||
|
||||
(trait_ref, lowered_ty)
|
||||
});
|
||||
@@ -458,7 +460,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
body: Option<&Expr>,
|
||||
) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
(ty, self.lower_const_body(span, body))
|
||||
}
|
||||
|
||||
@@ -608,8 +610,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
|
||||
}
|
||||
ForeignItemKind::Static(t, m, _) => {
|
||||
let ty =
|
||||
self.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty = self
|
||||
.lower_ty(t, &ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
hir::ForeignItemKind::Static(ty, *m)
|
||||
}
|
||||
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
|
||||
@@ -679,11 +681,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
qself,
|
||||
path,
|
||||
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
|
||||
);
|
||||
self.arena.alloc(t)
|
||||
} else {
|
||||
self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
|
||||
};
|
||||
let hir_id = self.lower_node_id(f.id);
|
||||
self.lower_attrs(hir_id, &f.attrs);
|
||||
@@ -708,7 +710,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let (generics, kind, has_default) = match &i.kind {
|
||||
AssocItemKind::Const(_, ty, default) => {
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
|
||||
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
|
||||
}
|
||||
@@ -746,7 +749,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = ty.as_ref().map(|x| {
|
||||
this.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
this.lower_ty(
|
||||
x,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
|
||||
)
|
||||
});
|
||||
hir::TraitItemKind::Type(
|
||||
this.lower_param_bounds(
|
||||
@@ -805,7 +811,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let (generics, kind) = match &i.kind {
|
||||
AssocItemKind::Const(_, ty, expr) => {
|
||||
let ty = self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
(
|
||||
hir::Generics::empty(),
|
||||
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
|
||||
@@ -1441,7 +1448,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir_id: self.next_id(),
|
||||
bound_generic_params: self.lower_generic_params(bound_generic_params),
|
||||
bounded_ty: self
|
||||
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||
self.lower_param_bound(
|
||||
bound,
|
||||
@@ -1465,9 +1472,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span }) => {
|
||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||
lhs_ty: self
|
||||
.lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
.lower_ty(lhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
rhs_ty: self
|
||||
.lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||
.lower_ty(rhs_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
|
||||
span: self.lower_span(*span),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -253,7 +253,6 @@ enum ImplTraitContext {
|
||||
enum ImplTraitPosition {
|
||||
Path,
|
||||
Variable,
|
||||
Type,
|
||||
Trait,
|
||||
AsyncBlock,
|
||||
Bound,
|
||||
@@ -270,6 +269,13 @@ enum ImplTraitPosition {
|
||||
FnTraitReturn,
|
||||
TraitReturn,
|
||||
ImplReturn,
|
||||
GenericDefault,
|
||||
ConstTy,
|
||||
StaticTy,
|
||||
AssocTy,
|
||||
FieldTy,
|
||||
Cast,
|
||||
ImplSelf,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ImplTraitPosition {
|
||||
@@ -277,7 +283,6 @@ impl std::fmt::Display for ImplTraitPosition {
|
||||
let name = match self {
|
||||
ImplTraitPosition::Path => "path",
|
||||
ImplTraitPosition::Variable => "variable binding",
|
||||
ImplTraitPosition::Type => "type",
|
||||
ImplTraitPosition::Trait => "trait",
|
||||
ImplTraitPosition::AsyncBlock => "async block",
|
||||
ImplTraitPosition::Bound => "bound",
|
||||
@@ -294,6 +299,13 @@ impl std::fmt::Display for ImplTraitPosition {
|
||||
ImplTraitPosition::FnTraitReturn => "`Fn` trait return",
|
||||
ImplTraitPosition::TraitReturn => "trait method return",
|
||||
ImplTraitPosition::ImplReturn => "`impl` method return",
|
||||
ImplTraitPosition::GenericDefault => "generic parameter default",
|
||||
ImplTraitPosition::ConstTy => "const type",
|
||||
ImplTraitPosition::StaticTy => "static type",
|
||||
ImplTraitPosition::AssocTy => "associated type",
|
||||
ImplTraitPosition::FieldTy => "field type",
|
||||
ImplTraitPosition::Cast => "cast type",
|
||||
ImplTraitPosition::ImplSelf => "impl header",
|
||||
};
|
||||
|
||||
write!(f, "{name}")
|
||||
@@ -2166,7 +2178,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
GenericParamKind::Type { default, .. } => {
|
||||
let kind = hir::GenericParamKind::Type {
|
||||
default: default.as_ref().map(|x| {
|
||||
self.lower_ty(x, &ImplTraitContext::Disallowed(ImplTraitPosition::Type))
|
||||
self.lower_ty(
|
||||
x,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
)
|
||||
}),
|
||||
synthetic: false,
|
||||
};
|
||||
@@ -2174,7 +2189,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
let ty = self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Type));
|
||||
let ty = self.lower_ty(
|
||||
&ty,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
|
||||
);
|
||||
let default = default.as_ref().map(|def| self.lower_anon_const(def));
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
|
||||
@@ -1144,7 +1144,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
|
||||
)
|
||||
&& infcx.can_eq(self.param_env, ty, self_ty).is_ok()
|
||||
&& infcx.can_eq(self.param_env, ty, self_ty)
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
fn_call_span.shrink_to_lo(),
|
||||
@@ -1182,8 +1182,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
);
|
||||
}
|
||||
let parent_did = tcx.parent(method_did);
|
||||
let parent_self_ty = (tcx.def_kind(parent_did)
|
||||
== rustc_hir::def::DefKind::Impl)
|
||||
let parent_self_ty =
|
||||
matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
|
||||
.then_some(parent_did)
|
||||
.and_then(|did| match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, ..) => Some(def.did()),
|
||||
|
||||
@@ -852,9 +852,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let region_parent = tcx.parent(region.def_id);
|
||||
if tcx.def_kind(region_parent) != DefKind::Impl {
|
||||
let DefKind::Impl { .. } = tcx.def_kind(region_parent) else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let found = tcx
|
||||
.any_free_region_meets(&tcx.type_of(region_parent), |r| *r == ty::ReEarlyBound(region));
|
||||
|
||||
@@ -640,7 +640,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => {
|
||||
intrinsic_args!(fx, args => (); intrinsic);
|
||||
|
||||
let layout = fx.layout_of(substs.type_at(0));
|
||||
let ty = substs.type_at(0);
|
||||
let layout = fx.layout_of(ty);
|
||||
if layout.abi.is_uninhabited() {
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
@@ -653,7 +654,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
}
|
||||
|
||||
if intrinsic == sym::assert_zero_valid
|
||||
&& !fx.tcx.permits_zero_init(fx.param_env().and(layout))
|
||||
&& !fx
|
||||
.tcx
|
||||
.permits_zero_init(fx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen")
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
@@ -669,7 +673,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
||||
}
|
||||
|
||||
if intrinsic == sym::assert_mem_uninitialized_valid
|
||||
&& !fx.tcx.permits_uninit_init(fx.param_env().and(layout))
|
||||
&& !fx
|
||||
.tcx
|
||||
.permits_uninit_init(fx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen")
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic_nounwind(
|
||||
|
||||
@@ -2,9 +2,8 @@ use std::collections::hash_map::Entry::*;
|
||||
|
||||
use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::middle::exported_symbols::{
|
||||
metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
|
||||
@@ -12,7 +11,7 @@ use rustc_middle::middle::exported_symbols::{
|
||||
use rustc_middle::ty::query::{ExternProviders, Providers};
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::{self, SymbolName, TyCtxt};
|
||||
use rustc_middle::ty::{self, DefIdTree, SymbolName, TyCtxt};
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
|
||||
@@ -74,33 +73,35 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
|
||||
//
|
||||
// As a result, if this id is an FFI item (foreign item) then we only
|
||||
// let it through if it's included statically.
|
||||
match tcx.hir().get_by_def_id(def_id) {
|
||||
Node::ForeignItem(..) => {
|
||||
tcx.native_library(def_id).map_or(false, |library| library.kind.is_statically_included()).then_some(def_id)
|
||||
if let Some(parent_id) = tcx.opt_local_parent(def_id)
|
||||
&& let DefKind::ForeignMod = tcx.def_kind(parent_id)
|
||||
{
|
||||
let library = tcx.native_library(def_id)?;
|
||||
return library.kind.is_statically_included().then_some(def_id);
|
||||
}
|
||||
|
||||
// Only consider nodes that actually have exported symbols.
|
||||
Node::Item(&hir::Item {
|
||||
kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn(..),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Fn | DefKind::Static(_) => {}
|
||||
DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
if !generics.requires_monomorphization(tcx)
|
||||
if generics.requires_monomorphization(tcx) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Functions marked with #[inline] are codegened with "internal"
|
||||
// linkage and are not exported unless marked with an extern
|
||||
// indicator
|
||||
&& (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator())
|
||||
if !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator()
|
||||
{
|
||||
Some(def_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.map(|def_id| {
|
||||
// We won't link right if this symbol is stripped during LTO.
|
||||
@@ -118,7 +119,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
|
||||
tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())),
|
||||
export_level
|
||||
);
|
||||
(def_id.to_def_id(), SymbolExportInfo {
|
||||
let info = SymbolExportInfo {
|
||||
level: export_level,
|
||||
kind: if tcx.is_static(def_id.to_def_id()) {
|
||||
if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
|
||||
@@ -130,8 +131,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
|
||||
SymbolExportKind::Text
|
||||
},
|
||||
used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || used,
|
||||
})
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
|| used,
|
||||
};
|
||||
(def_id.to_def_id(), info)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -457,9 +460,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
|
||||
let target = &tcx.sess.target.llvm_target;
|
||||
// WebAssembly cannot export data symbols, so reduce their export level
|
||||
if target.contains("emscripten") {
|
||||
if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })) =
|
||||
tcx.hir().get_if_local(sym_def_id)
|
||||
{
|
||||
if let DefKind::Static(_) = tcx.def_kind(sym_def_id) {
|
||||
return SymbolExportLevel::Rust;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,8 +674,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
let layout = bx.layout_of(ty);
|
||||
let do_panic = match intrinsic {
|
||||
Inhabited => layout.abi.is_uninhabited(),
|
||||
ZeroValid => !bx.tcx().permits_zero_init(bx.param_env().and(layout)),
|
||||
MemUninitializedValid => !bx.tcx().permits_uninit_init(bx.param_env().and(layout)),
|
||||
ZeroValid => !bx
|
||||
.tcx()
|
||||
.permits_zero_init(bx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen"),
|
||||
MemUninitializedValid => !bx
|
||||
.tcx()
|
||||
.permits_uninit_init(bx.param_env().and(ty))
|
||||
.expect("expected to have layout during codegen"),
|
||||
};
|
||||
Some(if do_panic {
|
||||
let msg_str = with_no_visible_paths!({
|
||||
|
||||
@@ -3,12 +3,12 @@ use rustc_attr::InstructionSetAttr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
@@ -440,12 +440,9 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxHashSet<Symbol> {
|
||||
/// Checks the function annotated with `#[target_feature]` is not a safe
|
||||
/// trait method implementation, reporting an error if it is.
|
||||
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
|
||||
let node = tcx.hir().get(hir_id);
|
||||
if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_item = tcx.hir().expect_item(parent_id.def_id);
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
|
||||
if let DefKind::AssocFn = tcx.def_kind(id) {
|
||||
let parent_id = tcx.local_parent(id);
|
||||
if let DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
attr_span,
|
||||
|
||||
@@ -186,7 +186,7 @@ pub(super) fn op_to_const<'tcx>(
|
||||
0,
|
||||
),
|
||||
};
|
||||
let len = b.to_machine_usize(ecx).unwrap();
|
||||
let len = b.to_target_usize(ecx).unwrap();
|
||||
let start = start.try_into().unwrap();
|
||||
let len: usize = len.try_into().unwrap();
|
||||
ConstValue::Slice { data, start, end: start + len }
|
||||
|
||||
@@ -17,7 +17,8 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
||||
|
||||
pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
let parent_id = tcx.local_parent(def_id);
|
||||
tcx.def_kind(parent_id) == DefKind::Impl && tcx.constness(parent_id) == hir::Constness::Const
|
||||
matches!(tcx.def_kind(parent_id), DefKind::Impl { .. })
|
||||
&& tcx.constness(parent_id) == hir::Constness::Const
|
||||
}
|
||||
|
||||
/// Checks whether an item is considered to be `const`. If it is a constructor, it is const. If
|
||||
|
||||
@@ -244,7 +244,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
assert_eq!(args.len(), 2);
|
||||
|
||||
let ptr = self.read_pointer(&args[0])?;
|
||||
let target_align = self.read_scalar(&args[1])?.to_machine_usize(self)?;
|
||||
let target_align = self.read_scalar(&args[1])?.to_target_usize(self)?;
|
||||
|
||||
if !target_align.is_power_of_two() {
|
||||
throw_ub_format!("`align_offset` called with non-power-of-two align: {}", target_align);
|
||||
@@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
Ok(ControlFlow::Break(()))
|
||||
} else {
|
||||
// Not alignable in const, return `usize::MAX`.
|
||||
let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self);
|
||||
let usize_max = Scalar::from_target_usize(self.target_usize_max(), self);
|
||||
self.write_scalar(usize_max, dest)?;
|
||||
self.return_to_block(ret)?;
|
||||
Ok(ControlFlow::Break(()))
|
||||
@@ -470,8 +470,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
|
||||
}
|
||||
sym::const_allocate => {
|
||||
let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
|
||||
let align = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
|
||||
let size = ecx.read_scalar(&args[0])?.to_target_usize(ecx)?;
|
||||
let align = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?;
|
||||
|
||||
let align = match Align::from_bytes(align) {
|
||||
Ok(a) => a,
|
||||
@@ -487,8 +487,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
}
|
||||
sym::const_deallocate => {
|
||||
let ptr = ecx.read_pointer(&args[0])?;
|
||||
let size = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
|
||||
let align = ecx.read_scalar(&args[2])?.to_machine_usize(ecx)?;
|
||||
let size = ecx.read_scalar(&args[1])?.to_target_usize(ecx)?;
|
||||
let align = ecx.read_scalar(&args[2])?.to_target_usize(ecx)?;
|
||||
|
||||
let size = Size::from_bytes(size);
|
||||
let align = match Align::from_bytes(align) {
|
||||
|
||||
@@ -155,7 +155,7 @@ pub(crate) fn deref_mir_constant<'tcx>(
|
||||
// In case of unsized types, figure out the real type behind.
|
||||
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
|
||||
ty::Str => bug!("there's no sized equivalent of a `str`"),
|
||||
ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
|
||||
ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_target_usize(&tcx).unwrap()),
|
||||
_ => bug!(
|
||||
"type {} should not have metadata, but had {:?}",
|
||||
mplace.layout.ty,
|
||||
|
||||
@@ -239,7 +239,7 @@ fn create_pointee_place<'tcx>(
|
||||
MPlaceTy::from_aligned_ptr_with_meta(
|
||||
ptr.into(),
|
||||
layout,
|
||||
MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)),
|
||||
MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)),
|
||||
)
|
||||
} else {
|
||||
create_mplace_from_layout(ecx, ty)
|
||||
@@ -355,7 +355,7 @@ fn valtree_into_mplace<'tcx>(
|
||||
let imm = match inner_ty.kind() {
|
||||
ty::Slice(_) | ty::Str => {
|
||||
let len = valtree.unwrap_branch().len();
|
||||
let len_scalar = Scalar::from_machine_usize(len as u64, &tcx);
|
||||
let len_scalar = Scalar::from_target_usize(len as u64, &tcx);
|
||||
|
||||
Immediate::ScalarPair(
|
||||
Scalar::from_maybe_pointer((*pointee_place).ptr, &tcx),
|
||||
@@ -426,7 +426,7 @@ fn valtree_into_mplace<'tcx>(
|
||||
place
|
||||
.offset_with_meta(
|
||||
offset,
|
||||
MemPlaceMeta::Meta(Scalar::from_machine_usize(
|
||||
MemPlaceMeta::Meta(Scalar::from_target_usize(
|
||||
num_elems as u64,
|
||||
&tcx,
|
||||
)),
|
||||
|
||||
@@ -231,7 +231,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// First cast to usize.
|
||||
let scalar = src.to_scalar();
|
||||
let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
|
||||
let addr = addr.to_machine_usize(self)?;
|
||||
let addr = addr.to_target_usize(self)?;
|
||||
|
||||
// Then turn address into pointer.
|
||||
let ptr = M::ptr_from_addr_cast(&self, addr)?;
|
||||
|
||||
@@ -639,7 +639,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
ty::Slice(_) | ty::Str => {
|
||||
let len = metadata.unwrap_meta().to_machine_usize(self)?;
|
||||
let len = metadata.unwrap_meta().to_target_usize(self)?;
|
||||
let elem = layout.field(self, 0);
|
||||
|
||||
// Make sure the slice is not too big.
|
||||
|
||||
@@ -71,7 +71,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
||||
sym::pref_align_of => {
|
||||
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
|
||||
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
|
||||
ConstValue::from_machine_usize(layout.align.pref.bytes(), &tcx)
|
||||
ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
|
||||
}
|
||||
sym::type_id => {
|
||||
ensure_monomorphic_enough(tcx, tp_ty)?;
|
||||
@@ -79,7 +79,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
||||
}
|
||||
sym::variant_count => match tp_ty.kind() {
|
||||
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
|
||||
ty::Adt(adt, _) => ConstValue::from_machine_usize(adt.variants().len() as u64, &tcx),
|
||||
ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx),
|
||||
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||
throw_inval!(TooGeneric)
|
||||
}
|
||||
@@ -104,7 +104,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
||||
| ty::GeneratorWitnessMIR(_, _)
|
||||
| ty::Never
|
||||
| ty::Tuple(_)
|
||||
| ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
|
||||
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
|
||||
},
|
||||
other => bug!("`{}` is not a zero arg intrinsic", other),
|
||||
})
|
||||
@@ -156,7 +156,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
self.write_scalar(Scalar::from_machine_usize(result, self), dest)?;
|
||||
self.write_scalar(Scalar::from_target_usize(result, self), dest)?;
|
||||
}
|
||||
|
||||
sym::pref_align_of
|
||||
@@ -302,7 +302,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
sym::offset => {
|
||||
let ptr = self.read_pointer(&args[0])?;
|
||||
let offset_count = self.read_machine_isize(&args[1])?;
|
||||
let offset_count = self.read_target_isize(&args[1])?;
|
||||
let pointee_ty = substs.type_at(0);
|
||||
|
||||
let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
|
||||
@@ -310,7 +310,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
sym::arith_offset => {
|
||||
let ptr = self.read_pointer(&args[0])?;
|
||||
let offset_count = self.read_machine_isize(&args[1])?;
|
||||
let offset_count = self.read_target_isize(&args[1])?;
|
||||
let pointee_ty = substs.type_at(0);
|
||||
|
||||
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
|
||||
@@ -376,7 +376,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// The signed form of the intrinsic allows this. If we interpret the
|
||||
// difference as isize, we'll get the proper signed difference. If that
|
||||
// seems *positive*, they were more than isize::MAX apart.
|
||||
let dist = val.to_machine_isize(self)?;
|
||||
let dist = val.to_target_isize(self)?;
|
||||
if dist >= 0 {
|
||||
throw_ub_format!(
|
||||
"`{}` called when first pointer is too far before second",
|
||||
@@ -386,7 +386,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
dist
|
||||
} else {
|
||||
// b >= a
|
||||
let dist = val.to_machine_isize(self)?;
|
||||
let dist = val.to_target_isize(self)?;
|
||||
// If converting to isize produced a *negative* result, we had an overflow
|
||||
// because they were more than isize::MAX apart.
|
||||
if dist < 0 {
|
||||
@@ -411,10 +411,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
// Perform division by size to compute return value.
|
||||
let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
|
||||
assert!(0 <= dist && dist <= self.machine_isize_max());
|
||||
assert!(0 <= dist && dist <= self.target_isize_max());
|
||||
usize_layout
|
||||
} else {
|
||||
assert!(self.machine_isize_min() <= dist && dist <= self.machine_isize_max());
|
||||
assert!(self.target_isize_min() <= dist && dist <= self.target_isize_max());
|
||||
isize_layout
|
||||
};
|
||||
let pointee_layout = self.layout_of(substs.type_at(0))?;
|
||||
@@ -448,7 +448,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
if intrinsic_name == sym::assert_zero_valid {
|
||||
let should_panic = !self.tcx.permits_zero_init(self.param_env.and(layout));
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.permits_zero_init(self.param_env.and(ty))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
M::abort(
|
||||
@@ -462,7 +465,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
if intrinsic_name == sym::assert_mem_uninitialized_valid {
|
||||
let should_panic = !self.tcx.permits_uninit_init(self.param_env.and(layout));
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.permits_uninit_init(self.param_env.and(ty))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
M::abort(
|
||||
@@ -525,12 +531,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
sym::vtable_size => {
|
||||
let ptr = self.read_pointer(&args[0])?;
|
||||
let (size, _align) = self.get_vtable_size_and_align(ptr)?;
|
||||
self.write_scalar(Scalar::from_machine_usize(size.bytes(), self), dest)?;
|
||||
self.write_scalar(Scalar::from_target_usize(size.bytes(), self), dest)?;
|
||||
}
|
||||
sym::vtable_align => {
|
||||
let ptr = self.read_pointer(&args[0])?;
|
||||
let (_size, align) = self.get_vtable_size_and_align(ptr)?;
|
||||
self.write_scalar(Scalar::from_machine_usize(align.bytes(), self), dest)?;
|
||||
self.write_scalar(Scalar::from_target_usize(align.bytes(), self), dest)?;
|
||||
}
|
||||
|
||||
_ => return Ok(false),
|
||||
@@ -669,10 +675,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
|
||||
nonoverlapping: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
let count = self.read_machine_usize(&count)?;
|
||||
let count = self.read_target_usize(&count)?;
|
||||
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
|
||||
let (size, align) = (layout.size, layout.align.abi);
|
||||
// `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
|
||||
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
|
||||
// but no actual allocation can be big enough for the difference to be noticeable.
|
||||
let size = size.checked_mul(count, self).ok_or_else(|| {
|
||||
err_ub_format!(
|
||||
@@ -697,9 +703,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
let dst = self.read_pointer(&dst)?;
|
||||
let byte = self.read_scalar(&byte)?.to_u8()?;
|
||||
let count = self.read_machine_usize(&count)?;
|
||||
let count = self.read_target_usize(&count)?;
|
||||
|
||||
// `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max),
|
||||
// `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
|
||||
// but no actual allocation can be big enough for the difference to be noticeable.
|
||||
let len = layout
|
||||
.size
|
||||
|
||||
@@ -425,7 +425,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
throw_ub!(PointerOutOfBounds {
|
||||
alloc_id,
|
||||
alloc_size,
|
||||
ptr_offset: self.machine_usize_to_isize(offset.bytes()),
|
||||
ptr_offset: self.target_usize_to_isize(offset.bytes()),
|
||||
ptr_size: size,
|
||||
msg,
|
||||
})
|
||||
|
||||
@@ -52,7 +52,7 @@ impl<Prov: Provenance> Immediate<Prov> {
|
||||
}
|
||||
|
||||
pub fn new_slice(val: Scalar<Prov>, len: u64, cx: &impl HasDataLayout) -> Self {
|
||||
Immediate::ScalarPair(val, Scalar::from_machine_usize(len, cx))
|
||||
Immediate::ScalarPair(val, Scalar::from_target_usize(len, cx))
|
||||
}
|
||||
|
||||
pub fn new_dyn_trait(
|
||||
@@ -414,12 +414,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.read_scalar(op)?.to_pointer(self)
|
||||
}
|
||||
/// Read a pointer-sized unsigned integer from a place.
|
||||
pub fn read_machine_usize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, u64> {
|
||||
self.read_scalar(op)?.to_machine_usize(self)
|
||||
pub fn read_target_usize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, u64> {
|
||||
self.read_scalar(op)?.to_target_usize(self)
|
||||
}
|
||||
/// Read a pointer-sized signed integer from a place.
|
||||
pub fn read_machine_isize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, i64> {
|
||||
self.read_scalar(op)?.to_machine_isize(self)
|
||||
pub fn read_target_isize(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx, i64> {
|
||||
self.read_scalar(op)?.to_target_isize(self)
|
||||
}
|
||||
|
||||
/// Turn the wide MPlace into a string (must already be dereferenced!)
|
||||
|
||||
@@ -229,7 +229,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
|
||||
if self.layout.is_unsized() {
|
||||
// We need to consult `meta` metadata
|
||||
match self.layout.ty.kind() {
|
||||
ty::Slice(..) | ty::Str => self.mplace.meta.unwrap_meta().to_machine_usize(cx),
|
||||
ty::Slice(..) | ty::Str => self.mplace.meta.unwrap_meta().to_target_usize(cx),
|
||||
_ => bug!("len not supported on unsized type {:?}", self.layout.ty),
|
||||
}
|
||||
} else {
|
||||
@@ -756,7 +756,7 @@ where
|
||||
mutbl: Mutability,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
|
||||
let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
|
||||
let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
|
||||
let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
|
||||
|
||||
let ty = self.tcx.mk_ref(
|
||||
|
||||
@@ -319,7 +319,7 @@ where
|
||||
// implement this.
|
||||
ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)),
|
||||
ty::Slice(..) => {
|
||||
let len = Scalar::from_machine_usize(inner_len, self);
|
||||
let len = Scalar::from_target_usize(inner_len, self);
|
||||
(MemPlaceMeta::Meta(len), base.layout.ty)
|
||||
}
|
||||
_ => {
|
||||
@@ -363,7 +363,7 @@ where
|
||||
Index(local) => {
|
||||
let layout = self.layout_of(self.tcx.types.usize)?;
|
||||
let n = self.local_to_op(self.frame(), local, Some(layout))?;
|
||||
let n = self.read_machine_usize(&n)?;
|
||||
let n = self.read_target_usize(&n)?;
|
||||
self.place_index(base, n)?
|
||||
}
|
||||
ConstantIndex { offset, min_length, from_end } => {
|
||||
@@ -392,7 +392,7 @@ where
|
||||
Index(local) => {
|
||||
let layout = self.layout_of(self.tcx.types.usize)?;
|
||||
let n = self.local_to_op(self.frame(), local, Some(layout))?;
|
||||
let n = self.read_machine_usize(&n)?;
|
||||
let n = self.read_target_usize(&n)?;
|
||||
self.operand_index(base, n)?
|
||||
}
|
||||
ConstantIndex { offset, min_length, from_end } => {
|
||||
|
||||
@@ -242,7 +242,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let src = self.eval_place(place)?;
|
||||
let op = self.place_to_op(&src)?;
|
||||
let len = op.len(self)?;
|
||||
self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
|
||||
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
|
||||
}
|
||||
|
||||
Ref(_, borrow_kind, place) => {
|
||||
@@ -297,7 +297,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
mir::NullOp::SizeOf => layout.size.bytes(),
|
||||
mir::NullOp::AlignOf => layout.align.abi.bytes(),
|
||||
};
|
||||
self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
|
||||
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
|
||||
}
|
||||
|
||||
ShallowInitBox(ref operand, _) => {
|
||||
|
||||
@@ -348,7 +348,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
// FIXME: check if the type/trait match what ty::Dynamic says?
|
||||
}
|
||||
ty::Slice(..) | ty::Str => {
|
||||
let _len = meta.unwrap_meta().to_machine_usize(self.ecx)?;
|
||||
let _len = meta.unwrap_meta().to_target_usize(self.ecx)?;
|
||||
// We do not check that `len * elem_size <= isize::MAX`:
|
||||
// that is only required for references, and there it falls out of the
|
||||
// "dereferenceable" check performed by Stacked Borrows.
|
||||
|
||||
@@ -59,11 +59,8 @@ pub fn provide(providers: &mut Providers) {
|
||||
const_eval::deref_mir_constant(tcx, param_env, value)
|
||||
};
|
||||
providers.permits_uninit_init = |tcx, param_env_and_ty| {
|
||||
let (param_env, ty) = param_env_and_ty.into_parts();
|
||||
util::might_permit_raw_init(tcx, param_env, ty, InitKind::UninitMitigated0x01Fill)
|
||||
};
|
||||
providers.permits_zero_init = |tcx, param_env_and_ty| {
|
||||
let (param_env, ty) = param_env_and_ty.into_parts();
|
||||
util::might_permit_raw_init(tcx, param_env, ty, InitKind::Zero)
|
||||
util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::UninitMitigated0x01Fill)
|
||||
};
|
||||
providers.permits_zero_init =
|
||||
|tcx, param_env_and_ty| util::might_permit_raw_init(tcx, param_env_and_ty, InitKind::Zero);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
|
||||
|
||||
@@ -20,15 +20,14 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
||||
/// to the full uninit check).
|
||||
pub fn might_permit_raw_init<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
ty: TyAndLayout<'tcx>,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
kind: InitKind,
|
||||
) -> bool {
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
if tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
might_permit_raw_init_strict(ty, tcx, kind)
|
||||
might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind)
|
||||
} else {
|
||||
let layout_cx = LayoutCx { tcx, param_env };
|
||||
might_permit_raw_init_lax(ty, &layout_cx, kind)
|
||||
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
|
||||
might_permit_raw_init_lax(tcx.layout_of(param_env_and_ty)?, &layout_cx, kind)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +37,7 @@ fn might_permit_raw_init_strict<'tcx>(
|
||||
ty: TyAndLayout<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: InitKind,
|
||||
) -> bool {
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let machine = CompileTimeInterpreter::new(
|
||||
Limit::new(0),
|
||||
/*can_access_statics:*/ false,
|
||||
@@ -65,7 +64,7 @@ fn might_permit_raw_init_strict<'tcx>(
|
||||
// This does *not* actually check that references are dereferenceable, but since all types that
|
||||
// require dereferenceability also require non-null, we don't actually get any false negatives
|
||||
// due to this.
|
||||
cx.validate_operand(&ot).is_ok()
|
||||
Ok(cx.validate_operand(&ot).is_ok())
|
||||
}
|
||||
|
||||
/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
|
||||
@@ -74,7 +73,7 @@ fn might_permit_raw_init_lax<'tcx>(
|
||||
this: TyAndLayout<'tcx>,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
init_kind: InitKind,
|
||||
) -> bool {
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
match init_kind {
|
||||
InitKind::Zero => {
|
||||
@@ -103,20 +102,20 @@ fn might_permit_raw_init_lax<'tcx>(
|
||||
};
|
||||
if !valid {
|
||||
// This is definitely not okay.
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Special magic check for references and boxes (i.e., special pointer types).
|
||||
if let Some(pointee) = this.ty.builtin_deref(false) {
|
||||
let pointee = cx.layout_of(pointee.ty).expect("need to be able to compute layouts");
|
||||
let pointee = cx.layout_of(pointee.ty)?;
|
||||
// We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
|
||||
if pointee.align.abi.bytes() > 1 {
|
||||
// 0x01-filling is not aligned.
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
if pointee.size.bytes() > 0 {
|
||||
// A 'fake' integer pointer is not sufficiently dereferenceable.
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +128,9 @@ fn might_permit_raw_init_lax<'tcx>(
|
||||
}
|
||||
FieldsShape::Arbitrary { offsets, .. } => {
|
||||
for idx in 0..offsets.len() {
|
||||
if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind) {
|
||||
if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind)? {
|
||||
// We found a field that is unhappy with this kind of initialization.
|
||||
return false;
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,5 +147,5 @@ fn might_permit_raw_init_lax<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_metadata = { path = "../rustc_metadata" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_plugin_impl = { path = "../rustc_plugin_impl" }
|
||||
rustc_save_analysis = { path = "../rustc_save_analysis" }
|
||||
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_error_codes = { path = "../rustc_error_codes" }
|
||||
|
||||
@@ -25,13 +25,10 @@ use rustc_data_structures::sync::SeqCst;
|
||||
use rustc_errors::registry::{InvalidErrorCode, Registry};
|
||||
use rustc_errors::{ErrorGuaranteed, PResult, TerminalUrl};
|
||||
use rustc_feature::find_gated_cfg;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_save_analysis as save;
|
||||
use rustc_save_analysis::DumpHandler;
|
||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
|
||||
use rustc_session::cstore::MetadataLoader;
|
||||
@@ -343,22 +340,7 @@ fn run_compiler(
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt()?.enter(|tcx| {
|
||||
let result = tcx.analysis(());
|
||||
if sess.opts.unstable_opts.save_analysis {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
sess.time("save_analysis", || {
|
||||
save::process_crate(
|
||||
tcx,
|
||||
crate_name,
|
||||
&sess.io.input,
|
||||
None,
|
||||
DumpHandler::new(sess.io.output_dir.as_deref(), crate_name),
|
||||
)
|
||||
});
|
||||
}
|
||||
result
|
||||
})?;
|
||||
queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
|
||||
|
||||
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
|
||||
@@ -140,6 +140,18 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position
|
||||
|
||||
infer_region_explanation = {$pref_kind ->
|
||||
*[should_not_happen] [{$pref_kind}]
|
||||
[ref_valid_for] ...the reference is valid for
|
||||
[content_valid_for] ...but the borrowed content is only valid for
|
||||
[type_obj_valid_for] object type is valid for
|
||||
[source_pointer_valid_for] source pointer is only valid for
|
||||
[type_satisfy] type must satisfy
|
||||
[type_outlive] type must outlive
|
||||
[lf_param_instantiated_with] lifetime parameter instantiated with
|
||||
[lf_param_must_outlive] but lifetime parameter must outlive
|
||||
[lf_instantiated_with] lifetime instantiated with
|
||||
[lf_must_outlive] but lifetime must outlive
|
||||
[pointer_valid_for] the pointer is valid for
|
||||
[data_valid_for] but the referenced data is only valid for
|
||||
[empty] {""}
|
||||
}{$pref_kind ->
|
||||
[empty] {""}
|
||||
@@ -148,7 +160,6 @@ infer_region_explanation = {$pref_kind ->
|
||||
*[should_not_happen] [{$desc_kind}]
|
||||
[restatic] the static lifetime
|
||||
[revar] lifetime {$desc_arg}
|
||||
|
||||
[as_defined] the lifetime `{$desc_arg}` as defined here
|
||||
[as_defined_anon] the anonymous lifetime as defined here
|
||||
[defined_here] the anonymous lifetime defined here
|
||||
@@ -158,8 +169,16 @@ infer_region_explanation = {$pref_kind ->
|
||||
*[should_not_happen] [{$suff_kind}]
|
||||
[empty]{""}
|
||||
[continues] ...
|
||||
[req_by_binding] {" "}as required by this binding
|
||||
}
|
||||
|
||||
infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
|
||||
infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
|
||||
infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
|
||||
infer_lf_bound_not_satisfied = lifetime bound not satisfied
|
||||
infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
|
||||
infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
|
||||
|
||||
infer_mismatched_static_lifetime = incompatible lifetime on type
|
||||
infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
|
||||
infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
|
||||
@@ -308,3 +327,21 @@ infer_ril_introduced_here = `'static` requirement introduced here
|
||||
infer_ril_introduced_by = requirement introduced by this return type
|
||||
infer_ril_because_of = because of this returned expression
|
||||
infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
|
||||
|
||||
infer_where_remove = remove the `where` clause
|
||||
infer_where_copy_predicates = copy the `where` clause predicates from the trait
|
||||
|
||||
infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
|
||||
infer_srs_remove = consider removing this semicolon
|
||||
infer_srs_add = consider returning the local binding `{$ident}`
|
||||
infer_srs_add_one = consider returning one of these bindings
|
||||
|
||||
infer_await_both_futures = consider `await`ing on both `Future`s
|
||||
infer_await_future = consider `await`ing on the `Future`
|
||||
infer_await_note = calling an async function returns a future
|
||||
|
||||
infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
|
||||
infer_prlf_defined_without_sub = the lifetime defined here...
|
||||
infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
|
||||
infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here
|
||||
infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
save_analysis_could_not_open = Could not open `{$file_name}`: `{$err}`
|
||||
@@ -67,7 +67,6 @@ fluent_messages! {
|
||||
privacy => "../locales/en-US/privacy.ftl",
|
||||
query_system => "../locales/en-US/query_system.ftl",
|
||||
resolve => "../locales/en-US/resolve.ftl",
|
||||
save_analysis => "../locales/en-US/save_analysis.ftl",
|
||||
session => "../locales/en-US/session.ftl",
|
||||
symbol_mangling => "../locales/en-US/symbol_mangling.ftl",
|
||||
trait_selection => "../locales/en-US/trait_selection.ftl",
|
||||
|
||||
@@ -116,7 +116,9 @@ pub enum DefKind {
|
||||
LifetimeParam,
|
||||
/// A use of `global_asm!`.
|
||||
GlobalAsm,
|
||||
Impl,
|
||||
Impl {
|
||||
of_trait: bool,
|
||||
},
|
||||
Closure,
|
||||
Generator,
|
||||
}
|
||||
@@ -155,7 +157,7 @@ impl DefKind {
|
||||
DefKind::AnonConst => "constant expression",
|
||||
DefKind::InlineConst => "inline constant",
|
||||
DefKind::Field => "field",
|
||||
DefKind::Impl => "implementation",
|
||||
DefKind::Impl { .. } => "implementation",
|
||||
DefKind::Closure => "closure",
|
||||
DefKind::Generator => "generator",
|
||||
DefKind::ExternCrate => "extern crate",
|
||||
@@ -171,7 +173,7 @@ impl DefKind {
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Enum
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Use
|
||||
| DefKind::InlineConst
|
||||
| DefKind::ExternCrate => "an",
|
||||
@@ -216,7 +218,7 @@ impl DefKind {
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::ImplTraitPlaceholder => None,
|
||||
}
|
||||
}
|
||||
@@ -255,7 +257,7 @@ impl DefKind {
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Field
|
||||
| DefKind::TyParam
|
||||
| DefKind::ConstParam
|
||||
|
||||
@@ -116,7 +116,7 @@ impl Target {
|
||||
DefKind::Union => Target::Union,
|
||||
DefKind::Trait => Target::Trait,
|
||||
DefKind::TraitAlias => Target::TraitAlias,
|
||||
DefKind::Impl => Target::Impl,
|
||||
DefKind::Impl { .. } => Target::Impl,
|
||||
_ => panic!("impossible case reached"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1970,7 +1970,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
) = &qself.kind {
|
||||
// If the path segment already has type params, we want to overwrite
|
||||
// them.
|
||||
match &path.segments[..] {
|
||||
match &path.segments {
|
||||
// `segment` is the previous to last element on the path,
|
||||
// which would normally be the `enum` itself, while the last
|
||||
// `_` `PathSegment` corresponds to the variant.
|
||||
@@ -2232,7 +2232,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
tcx.erase_regions(impl_.self_ty()),
|
||||
tcx.erase_regions(qself_ty),
|
||||
)
|
||||
.is_ok()
|
||||
})
|
||||
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
|
||||
})
|
||||
@@ -2671,7 +2670,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
// `Self` in trait or type alias.
|
||||
assert_eq!(opt_self_ty, None);
|
||||
self.prohibit_generics(path.segments.iter(), |err| {
|
||||
if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments[..] {
|
||||
if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
|
||||
err.span_suggestion_verbose(
|
||||
ident.span.shrink_to_hi().to(args.span_ext),
|
||||
"the `Self` type doesn't accept type parameters",
|
||||
|
||||
@@ -21,7 +21,9 @@ use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, DefIdTree, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, Span};
|
||||
@@ -174,16 +176,8 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
Ok(l) => l,
|
||||
// Foreign statics that overflow their allowed size should emit an error
|
||||
Err(LayoutError::SizeOverflow(_))
|
||||
if {
|
||||
let node = tcx.hir().get_by_def_id(def_id);
|
||||
matches!(
|
||||
node,
|
||||
hir::Node::ForeignItem(hir::ForeignItem {
|
||||
kind: hir::ForeignItemKind::Static(..),
|
||||
..
|
||||
})
|
||||
)
|
||||
} =>
|
||||
if matches!(tcx.def_kind(def_id), DefKind::Static(_)
|
||||
if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
|
||||
{
|
||||
tcx.sess
|
||||
.struct_span_err(span, "extern static is too large for the current architecture")
|
||||
@@ -215,7 +209,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||
let item = tcx.hir().item(id);
|
||||
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
|
||||
tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item");
|
||||
tcx.sess.delay_span_bug(item.span, "expected opaque item");
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -529,45 +523,34 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||
check_enum(tcx, id.owner_id.def_id);
|
||||
}
|
||||
DefKind::Fn => {} // entirely within check_item_body
|
||||
DefKind::Impl => {
|
||||
let it = tcx.hir().item(id);
|
||||
let hir::ItemKind::Impl(impl_) = it.kind else { return };
|
||||
debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
|
||||
if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
|
||||
DefKind::Impl { of_trait } => {
|
||||
if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(id.owner_id) {
|
||||
check_impl_items_against_trait(
|
||||
tcx,
|
||||
it.span,
|
||||
it.owner_id.def_id,
|
||||
id.owner_id.def_id,
|
||||
impl_trait_ref.subst_identity(),
|
||||
&impl_.items,
|
||||
);
|
||||
check_on_unimplemented(tcx, it);
|
||||
check_on_unimplemented(tcx, id);
|
||||
}
|
||||
}
|
||||
DefKind::Trait => {
|
||||
let it = tcx.hir().item(id);
|
||||
let hir::ItemKind::Trait(_, _, _, _, items) = it.kind else {
|
||||
return;
|
||||
};
|
||||
check_on_unimplemented(tcx, it);
|
||||
let assoc_items = tcx.associated_items(id.owner_id);
|
||||
check_on_unimplemented(tcx, id);
|
||||
|
||||
for item in items.iter() {
|
||||
let item = tcx.hir().trait_item(item.id);
|
||||
match &item.kind {
|
||||
hir::TraitItemKind::Fn(sig, _) => {
|
||||
let abi = sig.header.abi;
|
||||
fn_maybe_err(tcx, item.ident.span, abi);
|
||||
for assoc_item in assoc_items.in_definition_order() {
|
||||
match assoc_item.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
let abi = tcx.fn_sig(assoc_item.def_id).skip_binder().abi();
|
||||
fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi);
|
||||
}
|
||||
hir::TraitItemKind::Type(.., Some(default)) => {
|
||||
let assoc_item = tcx.associated_item(item.owner_id);
|
||||
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
||||
let trait_substs =
|
||||
InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id());
|
||||
InternalSubsts::identity_for_item(tcx, id.owner_id.to_def_id());
|
||||
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
||||
tcx,
|
||||
assoc_item,
|
||||
assoc_item,
|
||||
default.span,
|
||||
tcx.mk_trait_ref(it.owner_id.to_def_id(), trait_substs),
|
||||
tcx.mk_trait_ref(id.owner_id.to_def_id(), trait_substs),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
@@ -679,7 +662,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
||||
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: hir::ItemId) {
|
||||
// an error would be reported if this fails.
|
||||
let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
|
||||
}
|
||||
@@ -689,7 +672,7 @@ pub(super) fn check_specialization_validity<'tcx>(
|
||||
trait_def: &ty::TraitDef,
|
||||
trait_item: &ty::AssocItem,
|
||||
impl_id: DefId,
|
||||
impl_item: &hir::ImplItemRef,
|
||||
impl_item: DefId,
|
||||
) {
|
||||
let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) else { return };
|
||||
let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {
|
||||
@@ -735,10 +718,8 @@ pub(super) fn check_specialization_validity<'tcx>(
|
||||
|
||||
fn check_impl_items_against_trait<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
full_impl_span: Span,
|
||||
impl_id: LocalDefId,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
impl_item_refs: &[hir::ImplItemRef],
|
||||
) {
|
||||
// If the trait reference itself is erroneous (so the compilation is going
|
||||
// to fail), skip checking the items here -- the `impl_item` table in `tcx`
|
||||
@@ -747,12 +728,14 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
return;
|
||||
}
|
||||
|
||||
let impl_item_refs = tcx.associated_item_def_ids(impl_id);
|
||||
|
||||
// Negative impls are not expected to have any items
|
||||
match tcx.impl_polarity(impl_id) {
|
||||
ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}
|
||||
ty::ImplPolarity::Negative => {
|
||||
if let [first_item_ref, ..] = impl_item_refs {
|
||||
let first_item_span = tcx.hir().impl_item(first_item_ref.id).span;
|
||||
let first_item_span = tcx.def_span(first_item_ref);
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
first_item_span,
|
||||
@@ -767,43 +750,27 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
|
||||
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
|
||||
|
||||
for impl_item in impl_item_refs {
|
||||
let ty_impl_item = tcx.associated_item(impl_item.id.owner_id);
|
||||
for &impl_item in impl_item_refs {
|
||||
let ty_impl_item = tcx.associated_item(impl_item);
|
||||
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
|
||||
tcx.associated_item(trait_item_id)
|
||||
} else {
|
||||
// Checked in `associated_item`.
|
||||
tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
|
||||
tcx.sess.delay_span_bug(tcx.def_span(impl_item), "missing associated item in trait");
|
||||
continue;
|
||||
};
|
||||
let impl_item_full = tcx.hir().impl_item(impl_item.id);
|
||||
match impl_item_full.kind {
|
||||
hir::ImplItemKind::Const(..) => {
|
||||
match ty_impl_item.kind {
|
||||
ty::AssocKind::Const => {
|
||||
let _ = tcx.compare_impl_const((
|
||||
impl_item.id.owner_id.def_id,
|
||||
impl_item.expect_local(),
|
||||
ty_impl_item.trait_item_def_id.unwrap(),
|
||||
));
|
||||
}
|
||||
hir::ImplItemKind::Fn(..) => {
|
||||
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
||||
compare_impl_method(
|
||||
tcx,
|
||||
&ty_impl_item,
|
||||
&ty_trait_item,
|
||||
impl_trait_ref,
|
||||
opt_trait_span,
|
||||
);
|
||||
ty::AssocKind::Fn => {
|
||||
compare_impl_method(tcx, &ty_impl_item, &ty_trait_item, impl_trait_ref);
|
||||
}
|
||||
hir::ImplItemKind::Type(impl_ty) => {
|
||||
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
|
||||
compare_impl_ty(
|
||||
tcx,
|
||||
&ty_impl_item,
|
||||
impl_ty.span,
|
||||
&ty_trait_item,
|
||||
impl_trait_ref,
|
||||
opt_trait_span,
|
||||
);
|
||||
ty::AssocKind::Type => {
|
||||
compare_impl_ty(tcx, &ty_impl_item, &ty_trait_item, impl_trait_ref);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,6 +805,8 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
|
||||
|
||||
if !is_implemented_here {
|
||||
let full_impl_span =
|
||||
tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id));
|
||||
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
|
||||
EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
|
||||
tcx,
|
||||
@@ -864,6 +833,8 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
}
|
||||
|
||||
if !missing_items.is_empty() {
|
||||
let full_impl_span =
|
||||
tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id));
|
||||
missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ use std::iter;
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `impl_m`: type of the method we are checking
|
||||
/// - `impl_m_span`: span to use for reporting errors
|
||||
/// - `trait_m`: the method in the trait
|
||||
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
|
||||
pub(super) fn compare_impl_method<'tcx>(
|
||||
@@ -41,23 +40,19 @@ pub(super) fn compare_impl_method<'tcx>(
|
||||
impl_m: &ty::AssocItem,
|
||||
trait_m: &ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_item_span: Option<Span>,
|
||||
) {
|
||||
debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
let impl_m_span = tcx.def_span(impl_m.def_id);
|
||||
|
||||
let _: Result<_, ErrorGuaranteed> = try {
|
||||
compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)?;
|
||||
compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false)?;
|
||||
compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?;
|
||||
compare_number_of_generics(tcx, impl_m, trait_m, false)?;
|
||||
compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
|
||||
compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
|
||||
compare_number_of_method_arguments(tcx, impl_m, trait_m)?;
|
||||
compare_synthetic_generics(tcx, impl_m, trait_m)?;
|
||||
compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span)?;
|
||||
compare_asyncness(tcx, impl_m, trait_m)?;
|
||||
compare_method_predicate_entailment(
|
||||
tcx,
|
||||
impl_m,
|
||||
impl_m_span,
|
||||
trait_m,
|
||||
impl_trait_ref,
|
||||
CheckImpliedWfMode::Check,
|
||||
@@ -131,11 +126,10 @@ pub(super) fn compare_impl_method<'tcx>(
|
||||
///
|
||||
/// Finally we register each of these predicates as an obligation and check that
|
||||
/// they hold.
|
||||
#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))]
|
||||
#[instrument(level = "debug", skip(tcx, impl_trait_ref))]
|
||||
fn compare_method_predicate_entailment<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m: &ty::AssocItem,
|
||||
impl_m_span: Span,
|
||||
trait_m: &ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
check_implied_wf: CheckImpliedWfMode,
|
||||
@@ -148,6 +142,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
// FIXME(@lcnr): remove that after removing `cause.body_id` from
|
||||
// obligations.
|
||||
let impl_m_def_id = impl_m.def_id.expect_local();
|
||||
let impl_m_span = tcx.def_span(impl_m_def_id);
|
||||
let cause = ObligationCause::new(
|
||||
impl_m_span,
|
||||
impl_m_def_id,
|
||||
@@ -315,7 +310,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
return compare_method_predicate_entailment(
|
||||
tcx,
|
||||
impl_m,
|
||||
impl_m_span,
|
||||
trait_m,
|
||||
impl_trait_ref,
|
||||
CheckImpliedWfMode::Skip,
|
||||
@@ -353,7 +347,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
return compare_method_predicate_entailment(
|
||||
tcx,
|
||||
impl_m,
|
||||
impl_m_span,
|
||||
trait_m,
|
||||
impl_trait_ref,
|
||||
CheckImpliedWfMode::Skip,
|
||||
@@ -535,9 +528,7 @@ enum CheckImpliedWfMode {
|
||||
fn compare_asyncness<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m: &ty::AssocItem,
|
||||
impl_m_span: Span,
|
||||
trait_m: &ty::AssocItem,
|
||||
trait_item_span: Option<Span>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
|
||||
match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
|
||||
@@ -549,9 +540,9 @@ fn compare_asyncness<'tcx>(
|
||||
}
|
||||
_ => {
|
||||
return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
|
||||
span: impl_m_span,
|
||||
span: tcx.def_span(impl_m.def_id),
|
||||
method_name: trait_m.name,
|
||||
trait_item_span,
|
||||
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
|
||||
}));
|
||||
}
|
||||
};
|
||||
@@ -606,7 +597,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
||||
|
||||
// First, check a few of the same things as `compare_impl_method`,
|
||||
// just so we don't ICE during substitution later.
|
||||
compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?;
|
||||
compare_number_of_generics(tcx, impl_m, trait_m, true)?;
|
||||
compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
|
||||
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
|
||||
|
||||
@@ -1094,7 +1085,6 @@ fn extract_spans_for_error_reporting<'tcx>(
|
||||
fn compare_self_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m: &ty::AssocItem,
|
||||
impl_m_span: Span,
|
||||
trait_m: &ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
@@ -1116,7 +1106,7 @@ fn compare_self_type<'tcx>(
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
|
||||
let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
|
||||
let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty);
|
||||
match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
|
||||
ExplicitSelf::ByValue => "self".to_owned(),
|
||||
ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
|
||||
@@ -1130,6 +1120,7 @@ fn compare_self_type<'tcx>(
|
||||
|
||||
(false, true) => {
|
||||
let self_descr = self_string(impl_m);
|
||||
let impl_m_span = tcx.def_span(impl_m.def_id);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
impl_m_span,
|
||||
@@ -1149,6 +1140,7 @@ fn compare_self_type<'tcx>(
|
||||
|
||||
(true, false) => {
|
||||
let self_descr = self_string(trait_m);
|
||||
let impl_m_span = tcx.def_span(impl_m.def_id);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
impl_m_span,
|
||||
@@ -1196,7 +1188,6 @@ fn compare_number_of_generics<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_: &ty::AssocItem,
|
||||
trait_: &ty::AssocItem,
|
||||
trait_span: Option<Span>,
|
||||
delay: bool,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
|
||||
@@ -1256,6 +1247,7 @@ fn compare_number_of_generics<'tcx>(
|
||||
.collect();
|
||||
(Some(arg_spans), impl_trait_spans)
|
||||
} else {
|
||||
let trait_span = tcx.hir().span_if_local(trait_.def_id);
|
||||
(trait_span.map(|s| vec![s]), vec![])
|
||||
};
|
||||
|
||||
@@ -1338,9 +1330,7 @@ fn compare_number_of_generics<'tcx>(
|
||||
fn compare_number_of_method_arguments<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_m: &ty::AssocItem,
|
||||
impl_m_span: Span,
|
||||
trait_m: &ty::AssocItem,
|
||||
trait_item_span: Option<Span>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let impl_m_fty = tcx.fn_sig(impl_m.def_id);
|
||||
let trait_m_fty = tcx.fn_sig(trait_m.def_id);
|
||||
@@ -1362,7 +1352,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
||||
}
|
||||
})
|
||||
})
|
||||
.or(trait_item_span);
|
||||
.or_else(|| tcx.hir().span_if_local(trait_m.def_id));
|
||||
|
||||
let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
|
||||
let pos = impl_number_args.saturating_sub(1);
|
||||
@@ -1377,7 +1367,7 @@ fn compare_number_of_method_arguments<'tcx>(
|
||||
arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
|
||||
}
|
||||
})
|
||||
.unwrap_or(impl_m_span);
|
||||
.unwrap_or_else(|| tcx.def_span(impl_m.def_id));
|
||||
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
@@ -1747,22 +1737,16 @@ pub(super) fn compare_impl_const_raw(
|
||||
pub(super) fn compare_impl_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_ty: &ty::AssocItem,
|
||||
impl_ty_span: Span,
|
||||
trait_ty: &ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_item_span: Option<Span>,
|
||||
) {
|
||||
debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
let _: Result<(), ErrorGuaranteed> = try {
|
||||
compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?;
|
||||
|
||||
compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
|
||||
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
|
||||
|
||||
let sp = tcx.def_span(impl_ty.def_id);
|
||||
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
|
||||
|
||||
check_type_bounds(tcx, trait_ty, impl_ty, impl_ty_span, impl_trait_ref)?;
|
||||
compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?;
|
||||
check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)?;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1771,7 +1755,6 @@ pub(super) fn compare_impl_ty<'tcx>(
|
||||
fn compare_type_predicate_entailment<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_ty: &ty::AssocItem,
|
||||
impl_ty_span: Span,
|
||||
trait_ty: &ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
@@ -1808,6 +1791,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
|
||||
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
||||
|
||||
let impl_ty_span = tcx.def_span(impl_ty_def_id);
|
||||
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
|
||||
let param_env = ty::ParamEnv::new(
|
||||
tcx.intern_predicates(&hybrid_preds.predicates),
|
||||
@@ -1873,7 +1857,6 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ty: &ty::AssocItem,
|
||||
impl_ty: &ty::AssocItem,
|
||||
impl_ty_span: Span,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
// Given
|
||||
@@ -2009,8 +1992,15 @@ pub(super) fn check_type_bounds<'tcx>(
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let assumed_wf_types =
|
||||
ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local());
|
||||
let impl_ty_span = match tcx.hir().get_by_def_id(impl_ty_def_id) {
|
||||
hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Type(_, Some(ty)),
|
||||
..
|
||||
}) => ty.span,
|
||||
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span,
|
||||
_ => bug!(),
|
||||
};
|
||||
let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id);
|
||||
|
||||
let normalize_cause = ObligationCause::new(
|
||||
impl_ty_span,
|
||||
|
||||
@@ -414,7 +414,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
// Check that sym actually points to a function. Later passes
|
||||
// depend on this.
|
||||
hir::InlineAsmOperand::SymFn { anon_const } => {
|
||||
let ty = self.tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
|
||||
let ty = self.tcx.type_of(anon_const.def_id);
|
||||
match ty.kind() {
|
||||
ty::Never | ty::Error(_) => {}
|
||||
ty::FnDef(..) => {}
|
||||
@@ -422,7 +422,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
let mut err =
|
||||
self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand");
|
||||
err.span_label(
|
||||
self.tcx.hir().span(anon_const.body.hir_id),
|
||||
self.tcx.def_span(anon_const.def_id),
|
||||
&format!("is {} `{}`", ty.kind().article(), ty),
|
||||
);
|
||||
err.help("`sym` operands must refer to either a function or a static");
|
||||
|
||||
@@ -75,7 +75,6 @@ pub use check::check_abi;
|
||||
use check::check_mod_item_types;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
@@ -169,27 +168,24 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
|
||||
}
|
||||
}
|
||||
|
||||
fn report_forbidden_specialization(
|
||||
tcx: TyCtxt<'_>,
|
||||
impl_item: &hir::ImplItemRef,
|
||||
parent_impl: DefId,
|
||||
) {
|
||||
fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
|
||||
let span = tcx.def_span(impl_item);
|
||||
let ident = tcx.item_name(impl_item);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
impl_item.span,
|
||||
span,
|
||||
E0520,
|
||||
"`{}` specializes an item from a parent `impl`, but \
|
||||
that item is not marked `default`",
|
||||
impl_item.ident
|
||||
"`{}` specializes an item from a parent `impl`, but that item is not marked `default`",
|
||||
ident,
|
||||
);
|
||||
err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident));
|
||||
err.span_label(span, format!("cannot specialize default item `{}`", ident));
|
||||
|
||||
match tcx.span_of_impl(parent_impl) {
|
||||
Ok(span) => {
|
||||
err.span_label(span, "parent `impl` is here");
|
||||
err.note(&format!(
|
||||
"to specialize, `{}` in the parent `impl` must be marked `default`",
|
||||
impl_item.ident
|
||||
ident
|
||||
));
|
||||
}
|
||||
Err(cname) => {
|
||||
|
||||
@@ -1716,7 +1716,7 @@ fn receiver_is_valid<'tcx>(
|
||||
let cause =
|
||||
ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver);
|
||||
|
||||
let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty).is_ok();
|
||||
let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty);
|
||||
|
||||
// `self: Self` is always valid.
|
||||
if can_eq_self(receiver_ty) {
|
||||
|
||||
@@ -202,8 +202,7 @@ fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId)
|
||||
fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
||||
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
|
||||
|
||||
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
|
||||
let span = tcx.hir().span(impl_hir_id);
|
||||
let span = tcx.def_span(impl_did);
|
||||
|
||||
let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
/// On-demand query: yields a map containing all types mapped to their inherent impls.
|
||||
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
|
||||
@@ -57,86 +56,76 @@ const ADD_ATTR: &str =
|
||||
"alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
|
||||
|
||||
impl<'tcx> InherentCollect<'tcx> {
|
||||
fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId, span: Span) {
|
||||
let impl_def_id = item.owner_id;
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
|
||||
if let Some(ty_def_id) = ty_def_id.as_local() {
|
||||
// Add the implementation to the mapping from implementation to base
|
||||
// type def ID, if there is a base type for this implementation and
|
||||
// the implementation does not have any associated traits.
|
||||
let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
|
||||
let vec = self.impls_map.inherent_impls.entry(ty_def_id).or_default();
|
||||
vec.push(impl_def_id.to_def_id());
|
||||
return;
|
||||
}
|
||||
|
||||
if self.tcx.features().rustc_attrs {
|
||||
let hir::ItemKind::Impl(&hir::Impl { items, .. }) = item.kind else {
|
||||
bug!("expected `impl` item: {:?}", item);
|
||||
};
|
||||
let items = self.tcx.associated_item_def_ids(impl_def_id);
|
||||
|
||||
if !self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
|
||||
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
impl_span,
|
||||
E0390,
|
||||
"cannot define inherent `impl` for a type outside of the crate where the type is defined",
|
||||
)
|
||||
.help(INTO_DEFINING_CRATE)
|
||||
.span_help(span, ADD_ATTR_TO_TY)
|
||||
.span_help(impl_span, ADD_ATTR_TO_TY)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
for impl_item in items {
|
||||
if !self
|
||||
.tcx
|
||||
.has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
|
||||
{
|
||||
for &impl_item in items {
|
||||
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
impl_span,
|
||||
E0390,
|
||||
"cannot define inherent `impl` for a type outside of the crate where the type is defined",
|
||||
)
|
||||
.help(INTO_DEFINING_CRATE)
|
||||
.span_help(self.tcx.hir().span(impl_item.id.hir_id()), ADD_ATTR)
|
||||
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) {
|
||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id.def_id);
|
||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
|
||||
} else {
|
||||
bug!("unexpected self type: {:?}", self_ty);
|
||||
}
|
||||
} else {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
impl_span,
|
||||
E0116,
|
||||
"cannot define inherent `impl` for a type outside of the crate \
|
||||
where the type is defined"
|
||||
)
|
||||
.span_label(span, "impl for type defined outside of crate.")
|
||||
.span_label(impl_span, "impl for type defined outside of crate.")
|
||||
.note("define and implement a trait or new type instead")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_primitive_impl(
|
||||
&mut self,
|
||||
impl_def_id: LocalDefId,
|
||||
ty: Ty<'tcx>,
|
||||
items: &[hir::ImplItemRef],
|
||||
span: Span,
|
||||
) {
|
||||
fn check_primitive_impl(&mut self, impl_def_id: LocalDefId, ty: Ty<'tcx>) {
|
||||
let items = self.tcx.associated_item_def_ids(impl_def_id);
|
||||
if !self.tcx.hir().rustc_coherence_is_core() {
|
||||
if self.tcx.features().rustc_attrs {
|
||||
for item in items {
|
||||
if !self
|
||||
.tcx
|
||||
.has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
|
||||
{
|
||||
for &impl_item in items {
|
||||
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
||||
let span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
@@ -144,12 +133,13 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
"cannot define inherent `impl` for primitive types outside of `core`",
|
||||
)
|
||||
.help(INTO_CORE)
|
||||
.span_help(item.span, ADD_ATTR)
|
||||
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let span = self.tcx.def_span(impl_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
@@ -177,35 +167,27 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
}
|
||||
|
||||
fn check_item(&mut self, id: hir::ItemId) {
|
||||
if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) {
|
||||
if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: false }) {
|
||||
return;
|
||||
}
|
||||
|
||||
let item = self.tcx.hir().item(id);
|
||||
let impl_span = self.tcx.hir().span(id.hir_id());
|
||||
let hir::ItemKind::Impl(hir::Impl { of_trait: None, items, .. }) = item.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
let self_ty = self.tcx.type_of(item.owner_id);
|
||||
let id = id.owner_id.def_id;
|
||||
let item_span = self.tcx.def_span(id);
|
||||
let self_ty = self.tcx.type_of(id);
|
||||
match *self_ty.kind() {
|
||||
ty::Adt(def, _) => {
|
||||
self.check_def_id(item, self_ty, def.did(), impl_span);
|
||||
}
|
||||
ty::Foreign(did) => {
|
||||
self.check_def_id(item, self_ty, did, impl_span);
|
||||
}
|
||||
ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
|
||||
ty::Foreign(did) => self.check_def_id(id, self_ty, did),
|
||||
ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
|
||||
self.check_def_id(item, self_ty, data.principal_def_id().unwrap(), impl_span);
|
||||
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
|
||||
}
|
||||
ty::Dynamic(..) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
impl_span,
|
||||
item_span,
|
||||
E0785,
|
||||
"cannot define inherent `impl` for a dyn auto trait"
|
||||
)
|
||||
.span_label(impl_span, "impl requires at least one non-auto trait")
|
||||
.span_label(item_span, "impl requires at least one non-auto trait")
|
||||
.note("define and implement a new trait or type instead")
|
||||
.emit();
|
||||
}
|
||||
@@ -221,18 +203,16 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
| ty::Ref(..)
|
||||
| ty::Never
|
||||
| ty::FnPtr(_)
|
||||
| ty::Tuple(..) => {
|
||||
self.check_primitive_impl(item.owner_id.def_id, self_ty, items, impl_span)
|
||||
}
|
||||
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
|
||||
ty::Alias(..) | ty::Param(_) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
impl_span,
|
||||
item_span,
|
||||
E0118,
|
||||
"no nominal type found for inherent implementation"
|
||||
);
|
||||
|
||||
err.span_label(impl_span, "impl requires a nominal type")
|
||||
err.span_label(item_span, "impl requires a nominal type")
|
||||
.note("either implement a trait on it or create a newtype to wrap it instead");
|
||||
|
||||
err.emit();
|
||||
@@ -245,7 +225,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => {
|
||||
bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty);
|
||||
bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
|
||||
}
|
||||
ty::Error(_) => {}
|
||||
}
|
||||
|
||||
@@ -39,16 +39,17 @@ fn do_orphan_check_impl<'tcx>(
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
|
||||
match traits::orphan_check(tcx, def_id.to_def_id()) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
let item = tcx.hir().expect_item(def_id);
|
||||
let hir::ItemKind::Impl(impl_) = item.kind else {
|
||||
bug!("{:?} is not an impl: {:?}", def_id, item);
|
||||
};
|
||||
let sp = tcx.def_span(def_id);
|
||||
let tr = impl_.of_trait.as_ref().unwrap();
|
||||
let sp = tcx.def_span(def_id);
|
||||
|
||||
match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
|
||||
Ok(()) => {}
|
||||
Err(err) => emit_orphan_check_error(
|
||||
emit_orphan_check_error(
|
||||
tcx,
|
||||
sp,
|
||||
item.span,
|
||||
@@ -57,7 +58,8 @@ fn do_orphan_check_impl<'tcx>(
|
||||
impl_.self_ty.span,
|
||||
&impl_.generics,
|
||||
err,
|
||||
)?,
|
||||
)?
|
||||
}
|
||||
}
|
||||
|
||||
// In addition to the above rules, we restrict impls of auto traits
|
||||
@@ -235,7 +237,10 @@ fn do_orphan_check_impl<'tcx>(
|
||||
| ty::GeneratorWitnessMIR(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(..) => span_bug!(sp, "weird self type for autotrait impl"),
|
||||
| ty::Infer(..) => {
|
||||
let sp = tcx.def_span(def_id);
|
||||
span_bug!(sp, "weird self type for autotrait impl")
|
||||
}
|
||||
|
||||
ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
|
||||
};
|
||||
@@ -254,6 +259,7 @@ fn do_orphan_check_impl<'tcx>(
|
||||
is one of the trait object's trait bounds",
|
||||
trait = tcx.def_path_str(trait_def_id),
|
||||
);
|
||||
let sp = tcx.def_span(def_id);
|
||||
let reported =
|
||||
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
|
||||
return Err(reported);
|
||||
@@ -282,6 +288,7 @@ fn do_orphan_check_impl<'tcx>(
|
||||
non-struct/enum type",
|
||||
)),
|
||||
} {
|
||||
let sp = tcx.def_span(def_id);
|
||||
let reported =
|
||||
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
|
||||
return Err(reported);
|
||||
|
||||
@@ -1563,7 +1563,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
|
||||
// there being no supertrait HRTBs.
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl => {}
|
||||
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
|
||||
_ => break None,
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let min_specialization = tcx.features().min_specialization;
|
||||
let module = tcx.hir_module_items(module_def_id);
|
||||
for id in module.items() {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) {
|
||||
enforce_impl_params_are_constrained(tcx, id.owner_id.def_id);
|
||||
if min_specialization {
|
||||
check_min_specialization(tcx, id.owner_id.def_id);
|
||||
|
||||
@@ -298,6 +298,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// call's arguments and we can provide a more explicit span.
|
||||
let sig = self.tcx.fn_sig(def_id).subst_identity();
|
||||
let def_self_ty = sig.input(0).skip_binder();
|
||||
let param_tys = sig.inputs().skip_binder().iter().skip(1);
|
||||
// If there's an arity mismatch, pointing out the call as the source of an inference
|
||||
// can be misleading, so we skip it.
|
||||
if param_tys.len() != args.len() {
|
||||
continue;
|
||||
}
|
||||
let rcvr_ty = self.node_ty(rcvr.hir_id);
|
||||
// Get the evaluated type *after* calling the method call, so that the influence
|
||||
// of the arguments can be reflected in the receiver type. The receiver
|
||||
@@ -321,15 +327,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let mut param_args = FxHashMap::default();
|
||||
let mut param_expected = FxHashMap::default();
|
||||
let mut param_found = FxHashMap::default();
|
||||
if self.can_eq(self.param_env, ty, found).is_ok() {
|
||||
if self.can_eq(self.param_env, ty, found) {
|
||||
// We only point at the first place where the found type was inferred.
|
||||
for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() {
|
||||
for (param_ty, arg) in param_tys.zip(args) {
|
||||
if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() {
|
||||
// We found an argument that references a type parameter in `Self`,
|
||||
// so we assume that this is the argument that caused the found
|
||||
// type, which we know already because of `can_eq` above was first
|
||||
// inferred in this method call.
|
||||
let arg = &args[i];
|
||||
let arg_ty = self.node_ty(arg.hir_id);
|
||||
if !arg.span.overlaps(mismatch_span) {
|
||||
err.span_label(
|
||||
@@ -369,7 +374,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
for (param, (arg, arg_ty)) in param_args.iter() {
|
||||
let Some(expected) = param_expected.get(param) else { continue; };
|
||||
let Some(found) = param_found.get(param) else { continue; };
|
||||
if self.can_eq(self.param_env, *arg_ty, *found).is_err() { continue; }
|
||||
if !self.can_eq(self.param_env, *arg_ty, *found) { continue; }
|
||||
self.emit_coerce_suggestions(err, arg, *found, *expected, None, None);
|
||||
}
|
||||
|
||||
@@ -379,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
if ty != prev
|
||||
&& param_args.is_empty()
|
||||
&& self.can_eq(self.param_env, ty, found).is_ok()
|
||||
&& self.can_eq(self.param_env, ty, found)
|
||||
{
|
||||
// We only point at the first place where the found type was inferred.
|
||||
if !segment.ident.span.overlaps(mismatch_span) {
|
||||
@@ -401,7 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
if ty != prev
|
||||
&& let Some(span) = prev_span
|
||||
&& self.can_eq(self.param_env, ty, found).is_ok()
|
||||
&& self.can_eq(self.param_env, ty, found)
|
||||
{
|
||||
// We only point at the first place where the found type was inferred.
|
||||
// We use the *previous* span because if the type is known *here* it means
|
||||
@@ -764,7 +769,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if let ty::Adt(expected_adt, substs) = expected.kind() {
|
||||
if let hir::ExprKind::Field(base, ident) = expr.kind {
|
||||
let base_ty = self.typeck_results.borrow().expr_ty(base);
|
||||
if self.can_eq(self.param_env, base_ty, expected).is_ok()
|
||||
if self.can_eq(self.param_env, base_ty, expected)
|
||||
&& let Some(base_span) = base.span.find_ancestor_inside(expr.span)
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
@@ -1357,7 +1362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
|
||||
_,
|
||||
&ty::Ref(_, checked, _),
|
||||
) if self.can_sub(self.param_env, checked, expected).is_ok() => {
|
||||
) if self.can_sub(self.param_env, checked, expected) => {
|
||||
// We have `&T`, check if what was expected was `T`. If so,
|
||||
// we may want to suggest removing a `&`.
|
||||
if sm.is_imported(expr.span) {
|
||||
@@ -2003,7 +2008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
|
||||
let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; };
|
||||
if self.can_eq(self.param_env, expected_ty, ty).is_ok() {
|
||||
if self.can_eq(self.param_env, expected_ty, ty) {
|
||||
err.span_suggestion_short(
|
||||
stmt.span.with_lo(tail_expr.span.hi()),
|
||||
"remove this semicolon",
|
||||
|
||||
@@ -1015,7 +1015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let expr_inner_ty = substs.type_at(0);
|
||||
let expected_inner_ty = expected_substs.type_at(0);
|
||||
if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind()
|
||||
&& self.can_eq(self.param_env, *ty, expected_inner_ty).is_ok()
|
||||
&& self.can_eq(self.param_env, *ty, expected_inner_ty)
|
||||
{
|
||||
let def_path = self.tcx.def_path_str(adt_def.did());
|
||||
if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) {
|
||||
@@ -1054,7 +1054,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
|
||||
&& adt_def.did() == result_did
|
||||
// Check that the error types are equal
|
||||
&& self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
|
||||
&& self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1))
|
||||
{
|
||||
return suggest_copied_or_cloned();
|
||||
} else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
|
||||
|
||||
@@ -517,8 +517,7 @@ fn method_autoderef_steps<'tcx>(
|
||||
.by_ref()
|
||||
.map(|(ty, d)| {
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty),
|
||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
@@ -936,7 +935,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.can_sub(self.param_env, fty.output(), expected).is_ok()
|
||||
self.can_sub(self.param_env, fty.output(), expected)
|
||||
}),
|
||||
_ => false,
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
|
||||
if let Some(expr) = ti.origin_expr {
|
||||
self.suggest_fn_call(&mut diag, expr, expected, |output| {
|
||||
self.can_eq(self.param_env, output, actual).is_ok()
|
||||
self.can_eq(self.param_env, output, actual)
|
||||
});
|
||||
}
|
||||
Some(diag)
|
||||
@@ -675,7 +675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) {
|
||||
match (expected.kind(), actual.kind(), ba) {
|
||||
(ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE)
|
||||
if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
|
||||
if self.can_eq(self.param_env, *inner_ty, actual) =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
@@ -685,7 +685,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
(_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF)
|
||||
if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
|
||||
if self.can_eq(self.param_env, expected, *inner_ty) =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.lo() + BytePos(4)),
|
||||
|
||||
@@ -933,3 +933,216 @@ pub struct ButNeedsToSatisfy {
|
||||
pub has_lifetime: bool,
|
||||
pub lifetime: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_outlives_content, code = "E0312")]
|
||||
pub struct OutlivesContent<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_outlives_bound, code = "E0476")]
|
||||
pub struct OutlivesBound<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_fullfill_req_lifetime, code = "E0477")]
|
||||
pub struct FullfillReqLifetime<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
#[subdiagnostic]
|
||||
pub note: Option<note_and_explain::RegionExplanation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_lf_bound_not_satisfied, code = "E0478")]
|
||||
pub struct LfBoundNotSatisfied<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(infer_ref_longer_than_data, code = "E0491")]
|
||||
pub struct RefLongerThanData<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
#[subdiagnostic]
|
||||
pub notes: Vec<note_and_explain::RegionExplanation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum WhereClauseSuggestions {
|
||||
#[suggestion(
|
||||
infer_where_remove,
|
||||
code = "",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
Remove {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_where_copy_predicates,
|
||||
code = "{space}where {trait_predicates}",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
CopyPredicates {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
space: &'static str,
|
||||
trait_predicates: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum SuggestRemoveSemiOrReturnBinding {
|
||||
#[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")]
|
||||
RemoveAndBox {
|
||||
#[suggestion_part(code = "Box::new(")]
|
||||
first_lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
first_hi: Span,
|
||||
#[suggestion_part(code = "Box::new(")]
|
||||
second_lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
second_hi: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
sp: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_srs_remove,
|
||||
style = "short",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
Remove {
|
||||
#[primary_span]
|
||||
sp: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_srs_add,
|
||||
style = "verbose",
|
||||
code = "{code}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Add {
|
||||
#[primary_span]
|
||||
sp: Span,
|
||||
code: String,
|
||||
ident: Ident,
|
||||
},
|
||||
#[note(infer_srs_add_one)]
|
||||
AddOne {
|
||||
#[primary_span]
|
||||
spans: MultiSpan,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ConsiderAddingAwait {
|
||||
#[help(infer_await_both_futures)]
|
||||
BothFuturesHelp,
|
||||
#[multipart_suggestion(infer_await_both_futures, applicability = "maybe-incorrect")]
|
||||
BothFuturesSugg {
|
||||
#[suggestion_part(code = ".await")]
|
||||
first: Span,
|
||||
#[suggestion_part(code = ".await")]
|
||||
second: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
infer_await_future,
|
||||
code = ".await",
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
FutureSugg {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(infer_await_note)]
|
||||
FutureSuggNote {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(
|
||||
infer_await_future,
|
||||
style = "verbose",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
FutureSuggMultiple {
|
||||
#[suggestion_part(code = ".await")]
|
||||
spans: Vec<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub enum PlaceholderRelationLfNotSatisfied {
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasBoth {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_with_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_with_sup)]
|
||||
sup_span: Span,
|
||||
sub_symbol: Symbol,
|
||||
sup_symbol: Symbol,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasSub {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_with_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_without_sup)]
|
||||
sup_span: Span,
|
||||
sub_symbol: Symbol,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasSup {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_without_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_with_sup)]
|
||||
sup_span: Span,
|
||||
sup_symbol: Symbol,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
HasNone {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_defined_without_sub)]
|
||||
sub_span: Span,
|
||||
#[note(infer_prlf_must_oultive_without_sup)]
|
||||
sup_span: Span,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
#[diag(infer_lf_bound_not_satisfied)]
|
||||
OnlyPrimarySpan {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[note(infer_prlf_known_limitation)]
|
||||
note: (),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -121,16 +121,42 @@ impl<'a> DescriptionCtx<'a> {
|
||||
|
||||
pub enum PrefixKind {
|
||||
Empty,
|
||||
RefValidFor,
|
||||
ContentValidFor,
|
||||
TypeObjValidFor,
|
||||
SourcePointerValidFor,
|
||||
TypeSatisfy,
|
||||
TypeOutlive,
|
||||
LfParamInstantiatedWith,
|
||||
LfParamMustOutlive,
|
||||
LfInstantiatedWith,
|
||||
LfMustOutlive,
|
||||
PointerValidFor,
|
||||
DataValidFor,
|
||||
}
|
||||
|
||||
pub enum SuffixKind {
|
||||
Empty,
|
||||
Continues,
|
||||
ReqByBinding,
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for PrefixKind {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
let kind = match self {
|
||||
Self::Empty => "empty",
|
||||
Self::RefValidFor => "ref_valid_for",
|
||||
Self::ContentValidFor => "content_valid_for",
|
||||
Self::TypeObjValidFor => "type_obj_valid_for",
|
||||
Self::SourcePointerValidFor => "source_pointer_valid_for",
|
||||
Self::TypeSatisfy => "type_satisfy",
|
||||
Self::TypeOutlive => "type_outlive",
|
||||
Self::LfParamInstantiatedWith => "lf_param_instantiated_with",
|
||||
Self::LfParamMustOutlive => "lf_param_must_outlive",
|
||||
Self::LfInstantiatedWith => "lf_instantiated_with",
|
||||
Self::LfMustOutlive => "lf_must_outlive",
|
||||
Self::PointerValidFor => "pointer_valid_for",
|
||||
Self::DataValidFor => "data_valid_for",
|
||||
}
|
||||
.into();
|
||||
rustc_errors::DiagnosticArgValue::Str(kind)
|
||||
@@ -140,7 +166,9 @@ impl IntoDiagnosticArg for PrefixKind {
|
||||
impl IntoDiagnosticArg for SuffixKind {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
let kind = match self {
|
||||
Self::Empty => "empty",
|
||||
Self::Continues => "continues",
|
||||
Self::ReqByBinding => "req_by_binding",
|
||||
}
|
||||
.into();
|
||||
rustc_errors::DiagnosticArgValue::Str(kind)
|
||||
@@ -166,17 +194,19 @@ impl RegionExplanation<'_> {
|
||||
}
|
||||
|
||||
impl AddToDiagnostic for RegionExplanation<'_> {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
|
||||
where
|
||||
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
|
||||
{
|
||||
if let Some(span) = self.desc.span {
|
||||
diag.span_note(span, fluent::infer_region_explanation);
|
||||
} else {
|
||||
diag.note(fluent::infer_region_explanation);
|
||||
}
|
||||
self.desc.add_to(diag);
|
||||
diag.set_arg("pref_kind", self.prefix);
|
||||
diag.set_arg("suff_kind", self.suffix);
|
||||
let desc_span = self.desc.span;
|
||||
self.desc.add_to(diag);
|
||||
let msg = f(diag, fluent::infer_region_explanation.into());
|
||||
if let Some(span) = desc_span {
|
||||
diag.span_note(span, msg);
|
||||
} else {
|
||||
diag.note(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,15 +751,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
};
|
||||
let msg = "`match` arms have incompatible types";
|
||||
err.span_label(outer, msg);
|
||||
self.suggest_remove_semi_or_return_binding(
|
||||
err,
|
||||
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||
prior_arm_block_id,
|
||||
prior_arm_ty,
|
||||
prior_arm_span,
|
||||
arm_block_id,
|
||||
arm_ty,
|
||||
arm_span,
|
||||
);
|
||||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
// Get return type span and point to it.
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
@@ -784,15 +785,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
if let Some(sp) = outer_span {
|
||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
||||
}
|
||||
self.suggest_remove_semi_or_return_binding(
|
||||
err,
|
||||
if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
|
||||
Some(then_id),
|
||||
then_ty,
|
||||
then_span,
|
||||
Some(else_id),
|
||||
else_ty,
|
||||
else_span,
|
||||
);
|
||||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
|
||||
@@ -1061,7 +1061,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let parent_def_id = generics.parent.unwrap();
|
||||
if tcx.def_kind(parent_def_id) == DefKind::Impl {
|
||||
if let DefKind::Impl { .. } = tcx.def_kind(parent_def_id) {
|
||||
let parent_ty = tcx.bound_type_of(parent_def_id).subst(tcx, substs);
|
||||
match (parent_ty.kind(), &ty.kind) {
|
||||
(
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::infer::{
|
||||
use crate::{
|
||||
errors::PlaceholderRelationLfNotSatisfied,
|
||||
infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
|
||||
},
|
||||
};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
|
||||
@@ -16,8 +19,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
||||
Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
|
||||
Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
|
||||
)) => {
|
||||
let msg = "lifetime bound not satisfied";
|
||||
let mut err = self.tcx().sess.struct_span_err(*span, msg);
|
||||
let span = *span;
|
||||
let (sub_span, sub_symbol) = match sub_name {
|
||||
ty::BrNamed(def_id, symbol) => {
|
||||
(Some(self.tcx().def_span(def_id)), Some(symbol))
|
||||
@@ -32,41 +34,47 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
||||
ty::BrAnon(_, span) => (*span, None),
|
||||
ty::BrEnv => (None, None),
|
||||
};
|
||||
match (sub_span, sup_span, sub_symbol, sup_symbol) {
|
||||
(Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
|
||||
err.span_note(
|
||||
let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
|
||||
(Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => {
|
||||
PlaceholderRelationLfNotSatisfied::HasBoth {
|
||||
span,
|
||||
sub_span,
|
||||
format!("the lifetime `{sub_symbol}` defined here..."),
|
||||
);
|
||||
err.span_note(
|
||||
sup_span,
|
||||
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
|
||||
);
|
||||
sub_symbol,
|
||||
sup_symbol,
|
||||
note: (),
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
|
||||
err.span_note(sub_span, "the lifetime defined here...");
|
||||
err.span_note(
|
||||
sup_span,
|
||||
format!("...must outlive the lifetime `{sup_symbol}` defined here"),
|
||||
);
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
|
||||
err.span_note(
|
||||
(Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => {
|
||||
PlaceholderRelationLfNotSatisfied::HasSup {
|
||||
span,
|
||||
sub_span,
|
||||
format!("the lifetime `{sub_symbol}` defined here..."),
|
||||
);
|
||||
err.span_note(sup_span, "...must outlive the lifetime defined here");
|
||||
sup_span,
|
||||
sup_symbol,
|
||||
note: (),
|
||||
}
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), Some(&sub_symbol), _) => {
|
||||
PlaceholderRelationLfNotSatisfied::HasSub {
|
||||
span,
|
||||
sub_span,
|
||||
sup_span,
|
||||
sub_symbol,
|
||||
note: (),
|
||||
}
|
||||
}
|
||||
(Some(sub_span), Some(sup_span), _, _) => {
|
||||
err.span_note(sub_span, "the lifetime defined here...");
|
||||
err.span_note(sup_span, "...must outlive the lifetime defined here");
|
||||
PlaceholderRelationLfNotSatisfied::HasNone {
|
||||
span,
|
||||
sub_span,
|
||||
sup_span,
|
||||
note: (),
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
|
||||
Some(err)
|
||||
_ => PlaceholderRelationLfNotSatisfied::OnlyPrimarySpan { span, note: () },
|
||||
};
|
||||
Some(self.tcx().sess.create_err(diag))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use crate::errors::RegionOriginNote;
|
||||
use crate::errors::{
|
||||
note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
|
||||
RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
|
||||
};
|
||||
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
||||
use crate::infer::{self, SubregionOrigin};
|
||||
use rustc_errors::{
|
||||
fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
|
||||
ErrorGuaranteed,
|
||||
fluent, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
|
||||
};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
@@ -119,130 +121,105 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
err
|
||||
}
|
||||
infer::Reborrow(span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0312,
|
||||
"lifetime of reference outlives lifetime of borrowed content..."
|
||||
);
|
||||
note_and_explain_region(
|
||||
let reference_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...the reference is valid for ",
|
||||
sub,
|
||||
"...",
|
||||
None,
|
||||
note_and_explain::PrefixKind::RefValidFor,
|
||||
note_and_explain::SuffixKind::Continues,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let content_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"...but the borrowed content is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::ContentValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
OutlivesContent {
|
||||
span,
|
||||
notes: reference_valid.into_iter().chain(content_valid).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::RelateObjectBound(span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0476,
|
||||
"lifetime of the source pointer does not outlive lifetime bound of the \
|
||||
object type"
|
||||
);
|
||||
note_and_explain_region(
|
||||
let object_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"object type is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::TypeObjValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let pointer_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"source pointer is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::SourcePointerValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
OutlivesBound {
|
||||
span,
|
||||
notes: object_valid.into_iter().chain(pointer_valid).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::RelateParamBound(span, ty, opt_span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0477,
|
||||
"the type `{}` does not fulfill the required lifetime",
|
||||
self.ty_to_string(ty)
|
||||
let prefix = match *sub {
|
||||
ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy,
|
||||
_ => note_and_explain::PrefixKind::TypeOutlive,
|
||||
};
|
||||
let suffix = if opt_span.is_some() {
|
||||
note_and_explain::SuffixKind::ReqByBinding
|
||||
} else {
|
||||
note_and_explain::SuffixKind::Empty
|
||||
};
|
||||
let note = note_and_explain::RegionExplanation::new(
|
||||
self.tcx, sub, opt_span, prefix, suffix,
|
||||
);
|
||||
match *sub {
|
||||
ty::ReStatic => note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"type must satisfy ",
|
||||
sub,
|
||||
if opt_span.is_some() { " as required by this binding" } else { "" },
|
||||
opt_span,
|
||||
),
|
||||
_ => note_and_explain_region(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"type must outlive ",
|
||||
sub,
|
||||
if opt_span.is_some() { " as required by this binding" } else { "" },
|
||||
opt_span,
|
||||
),
|
||||
}
|
||||
err
|
||||
FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
let param_instantiated = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime parameter instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfParamInstantiatedWith,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let param_must_outlive = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime parameter must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfParamMustOutlive,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
LfBoundNotSatisfied {
|
||||
span,
|
||||
notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0491,
|
||||
"in type `{}`, reference has a longer lifetime than the data it references",
|
||||
self.ty_to_string(ty)
|
||||
);
|
||||
note_and_explain_region(
|
||||
let pointer_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"the pointer is valid for ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::PointerValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let data_valid = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but the referenced data is only valid for ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::DataValidFor,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
RefLongerThanData {
|
||||
span,
|
||||
ty: self.resolve_vars_if_possible(ty),
|
||||
notes: pointer_valid.into_iter().chain(data_valid).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
|
||||
let mut err = self.report_extra_impl_obligation(
|
||||
@@ -279,25 +256,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
err
|
||||
}
|
||||
infer::AscribeUserTypeProvePredicate(span) => {
|
||||
let mut err =
|
||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
let instantiated = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"lifetime instantiated with ",
|
||||
sup,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfInstantiatedWith,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
note_and_explain_region(
|
||||
let must_outlive = note_and_explain::RegionExplanation::new(
|
||||
self.tcx,
|
||||
&mut err,
|
||||
"but lifetime must outlive ",
|
||||
sub,
|
||||
"",
|
||||
None,
|
||||
note_and_explain::PrefixKind::LfMustOutlive,
|
||||
note_and_explain::SuffixKind::Empty,
|
||||
);
|
||||
err
|
||||
LfBoundNotSatisfied {
|
||||
span,
|
||||
notes: instantiated.into_iter().chain(must_outlive).collect(),
|
||||
}
|
||||
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
|
||||
}
|
||||
};
|
||||
if sub.is_error() || sup.is_error() {
|
||||
@@ -347,22 +324,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
|
||||
|
||||
if trait_predicates.is_empty() {
|
||||
err.span_suggestion_verbose(
|
||||
generics.where_clause_span,
|
||||
"remove the `where` clause",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let suggestion = if trait_predicates.is_empty() {
|
||||
WhereClauseSuggestions::Remove { span: generics.where_clause_span }
|
||||
} else {
|
||||
let space = if generics.where_clause_span.is_empty() { " " } else { "" };
|
||||
err.span_suggestion_verbose(
|
||||
generics.where_clause_span,
|
||||
"copy the `where` clause predicates from the trait",
|
||||
format!("{space}where {}", trait_predicates.join(", ")),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
WhereClauseSuggestions::CopyPredicates {
|
||||
span: generics.where_clause_span,
|
||||
space,
|
||||
trait_predicates: trait_predicates.join(", "),
|
||||
}
|
||||
};
|
||||
err.subdiagnostic(suggestion);
|
||||
}
|
||||
|
||||
pub(super) fn report_placeholder_failure(
|
||||
|
||||
@@ -504,7 +504,9 @@ fn foo(&self) -> Self::T { String::new() }
|
||||
let methods: Vec<(Span, String)> = items
|
||||
.in_definition_order()
|
||||
.filter(|item| {
|
||||
ty::AssocKind::Fn == item.kind && Some(item.name) != current_method_ident
|
||||
ty::AssocKind::Fn == item.kind
|
||||
&& Some(item.name) != current_method_ident
|
||||
&& !tcx.is_doc_hidden(item.def_id)
|
||||
})
|
||||
.filter_map(|item| {
|
||||
let method = tcx.fn_sig(item.def_id).subst_identity();
|
||||
@@ -576,7 +578,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||
tcx.impl_defaultness(item.id.owner_id)
|
||||
{
|
||||
let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
|
||||
if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
|
||||
if self.infcx.can_eq(param_env, assoc_ty, found) {
|
||||
diag.span_label(
|
||||
item.span,
|
||||
"associated type defaults can't be assumed inside the \
|
||||
@@ -598,7 +600,7 @@ fn foo(&self) -> Self::T { String::new() }
|
||||
if let hir::AssocItemKind::Type = item.kind {
|
||||
let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
|
||||
|
||||
if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
|
||||
if self.infcx.can_eq(param_env, assoc_ty, found) {
|
||||
diag.span_label(item.span, "expected this associated type");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,21 +11,22 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
|
||||
use crate::errors::SuggAddLetForLetChains;
|
||||
use crate::errors::{
|
||||
ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding,
|
||||
};
|
||||
|
||||
use super::TypeErrCtxt;
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
pub(super) fn suggest_remove_semi_or_return_binding(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
first_id: Option<hir::HirId>,
|
||||
first_ty: Ty<'tcx>,
|
||||
first_span: Span,
|
||||
second_id: Option<hir::HirId>,
|
||||
second_ty: Ty<'tcx>,
|
||||
second_span: Span,
|
||||
) {
|
||||
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||
let remove_semicolon = [
|
||||
(first_id, self.resolve_vars_if_possible(second_ty)),
|
||||
(second_id, self.resolve_vars_if_possible(first_ty)),
|
||||
@@ -37,35 +38,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
});
|
||||
match remove_semicolon {
|
||||
Some((sp, StatementAsExpression::NeedsBoxing)) => {
|
||||
err.multipart_suggestion(
|
||||
"consider removing this semicolon and boxing the expressions",
|
||||
vec![
|
||||
(first_span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(first_span.shrink_to_hi(), ")".to_string()),
|
||||
(second_span.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(second_span.shrink_to_hi(), ")".to_string()),
|
||||
(sp, String::new()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
Some(SuggestRemoveSemiOrReturnBinding::RemoveAndBox {
|
||||
first_lo: first_span.shrink_to_lo(),
|
||||
first_hi: first_span.shrink_to_hi(),
|
||||
second_lo: second_span.shrink_to_lo(),
|
||||
second_hi: second_span.shrink_to_hi(),
|
||||
sp,
|
||||
})
|
||||
}
|
||||
Some((sp, StatementAsExpression::CorrectType)) => {
|
||||
err.span_suggestion_short(
|
||||
sp,
|
||||
"consider removing this semicolon",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
Some(SuggestRemoveSemiOrReturnBinding::Remove { sp })
|
||||
}
|
||||
None => {
|
||||
let mut ret = None;
|
||||
for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] {
|
||||
if let Some(id) = id
|
||||
&& let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
||||
&& self.consider_returning_binding(blk, ty, err)
|
||||
&& let Some(diag) = self.consider_returning_binding_diag(blk, ty)
|
||||
{
|
||||
ret = Some(diag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,7 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
match (
|
||||
let subdiag = match (
|
||||
self.get_impl_future_output_ty(exp_found.expected),
|
||||
self.get_impl_future_output_ty(exp_found.found),
|
||||
) {
|
||||
@@ -207,65 +202,56 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
{
|
||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
||||
let then_span = self.find_block_span_from_hir_id(*then_id);
|
||||
diag.multipart_suggestion(
|
||||
"consider `await`ing on both `Future`s",
|
||||
vec![
|
||||
(then_span.shrink_to_hi(), ".await".to_string()),
|
||||
(exp_span.shrink_to_hi(), ".await".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||
first: then_span.shrink_to_hi(),
|
||||
second: exp_span.shrink_to_hi(),
|
||||
})
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
prior_arms,
|
||||
..
|
||||
}) => {
|
||||
if let [.., arm_span] = &prior_arms[..] {
|
||||
diag.multipart_suggestion(
|
||||
"consider `await`ing on both `Future`s",
|
||||
vec![
|
||||
(arm_span.shrink_to_hi(), ".await".to_string()),
|
||||
(exp_span.shrink_to_hi(), ".await".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||
first: arm_span.shrink_to_hi(),
|
||||
second: exp_span.shrink_to_hi(),
|
||||
})
|
||||
} else {
|
||||
diag.help("consider `await`ing on both `Future`s");
|
||||
Some(ConsiderAddingAwait::BothFuturesHelp)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
diag.help("consider `await`ing on both `Future`s");
|
||||
}
|
||||
_ => Some(ConsiderAddingAwait::BothFuturesHelp),
|
||||
},
|
||||
(_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
|
||||
self.suggest_await_on_future(diag, exp_span);
|
||||
diag.span_note(exp_span, "calling an async function returns a future");
|
||||
// FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic
|
||||
diag.subdiagnostic(ConsiderAddingAwait::FutureSugg {
|
||||
span: exp_span.shrink_to_hi(),
|
||||
});
|
||||
Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span })
|
||||
}
|
||||
(Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
|
||||
{
|
||||
ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
|
||||
self.suggest_await_on_future(diag, then_span.shrink_to_hi());
|
||||
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
|
||||
}
|
||||
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
|
||||
let then_span = self.find_block_span_from_hir_id(*then_id);
|
||||
self.suggest_await_on_future(diag, then_span.shrink_to_hi());
|
||||
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
ref prior_arms,
|
||||
..
|
||||
}) => {
|
||||
diag.multipart_suggestion_verbose(
|
||||
"consider `await`ing on the `Future`",
|
||||
prior_arms
|
||||
.iter()
|
||||
.map(|arm| (arm.shrink_to_hi(), ".await".to_string()))
|
||||
.collect(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}) => Some({
|
||||
ConsiderAddingAwait::FutureSuggMultiple {
|
||||
spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
|
||||
}
|
||||
_ => {}
|
||||
}),
|
||||
_ => None,
|
||||
},
|
||||
_ => {}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(subdiag) = subdiag {
|
||||
diag.subdiagnostic(subdiag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,16 +641,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
/// Suggest returning a local binding with a compatible type if the block
|
||||
/// has no return expression.
|
||||
pub fn consider_returning_binding(
|
||||
pub fn consider_returning_binding_diag(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
) -> Option<SuggestRemoveSemiOrReturnBinding> {
|
||||
let blk = blk.innermost_block();
|
||||
// Do not suggest if we have a tail expr.
|
||||
if blk.expr.is_some() {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
let mut shadowed = FxIndexSet::default();
|
||||
let mut candidate_idents = vec![];
|
||||
@@ -733,7 +718,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
match &candidate_idents[..] {
|
||||
[(ident, _ty)] => {
|
||||
let sm = self.tcx.sess.source_map();
|
||||
if let Some(stmt) = blk.stmts.last() {
|
||||
let (span, sugg) = if let Some(stmt) = blk.stmts.last() {
|
||||
let stmt_span = sm.stmt_span(stmt.span, blk.span);
|
||||
let sugg = if sm.is_multiline(blk.span)
|
||||
&& let Some(spacing) = sm.indentation_before(stmt_span)
|
||||
@@ -742,12 +727,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
} else {
|
||||
format!(" {ident}")
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
stmt_span.shrink_to_hi(),
|
||||
format!("consider returning the local binding `{ident}`"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
(stmt_span.shrink_to_hi(), sugg)
|
||||
} else {
|
||||
let sugg = if sm.is_multiline(blk.span)
|
||||
&& let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
|
||||
@@ -757,21 +737,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
format!(" {ident} ")
|
||||
};
|
||||
let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
|
||||
err.span_suggestion_verbose(
|
||||
(
|
||||
sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
|
||||
format!("consider returning the local binding `{ident}`"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
true
|
||||
)
|
||||
};
|
||||
Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident })
|
||||
}
|
||||
values if (1..3).contains(&values.len()) => {
|
||||
let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
|
||||
err.span_note(spans, "consider returning one of these bindings");
|
||||
Some(SuggestRemoveSemiOrReturnBinding::AddOne { spans: spans.into() })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consider_returning_binding(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
let diag = self.consider_returning_binding_diag(blk, expected_ty);
|
||||
match diag {
|
||||
Some(diag) => {
|
||||
err.subdiagnostic(diag);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -880,30 +880,20 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
|
||||
}
|
||||
|
||||
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
|
||||
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
|
||||
where
|
||||
T: at::ToTrace<'tcx>,
|
||||
{
|
||||
let origin = &ObligationCause::dummy();
|
||||
self.probe(|_| {
|
||||
self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
|
||||
// Ignore obligations, since we are unrolling
|
||||
// everything anyway.
|
||||
})
|
||||
})
|
||||
self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok())
|
||||
}
|
||||
|
||||
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx>
|
||||
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
|
||||
where
|
||||
T: at::ToTrace<'tcx>,
|
||||
{
|
||||
let origin = &ObligationCause::dummy();
|
||||
self.probe(|_| {
|
||||
self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
|
||||
// Ignore obligations, since we are unrolling
|
||||
// everything anyway.
|
||||
})
|
||||
})
|
||||
self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok())
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
|
||||
@@ -691,7 +691,6 @@ fn test_unstable_options_tracking_hash() {
|
||||
untracked!(proc_macro_execution_strategy, ProcMacroExecutionStrategy::CrossThread);
|
||||
untracked!(profile_closures, true);
|
||||
untracked!(query_dep_graph, true);
|
||||
untracked!(save_analysis, true);
|
||||
untracked!(self_profile, SwitchWithOptPath::Enabled(None));
|
||||
untracked!(self_profile_events, Some(vec![String::new()]));
|
||||
untracked!(span_debug, true);
|
||||
|
||||
@@ -838,7 +838,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Field => true,
|
||||
DefKind::TyParam
|
||||
| DefKind::ConstParam
|
||||
@@ -873,7 +873,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Enum
|
||||
| DefKind::Union
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Trait
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::Macro(..)
|
||||
@@ -951,7 +951,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||
| DefKind::Const
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::TyAlias
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Trait
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::Macro(..)
|
||||
@@ -988,7 +988,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
|
||||
| DefKind::InlineConst
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Field
|
||||
| DefKind::TyParam
|
||||
| DefKind::Closure
|
||||
@@ -1018,7 +1018,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
|
||||
| DefKind::TyAlias
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Closure
|
||||
@@ -1081,7 +1081,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::ImplTraitPlaceholder
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator
|
||||
@@ -1860,7 +1860,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
FxHashMap::default();
|
||||
|
||||
for id in tcx.hir().items() {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) {
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
|
||||
@@ -2261,7 +2261,7 @@ pub fn provide(providers: &mut Providers) {
|
||||
|
||||
let mut trait_impls = Vec::new();
|
||||
for id in tcx.hir().items() {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl)
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. })
|
||||
&& tcx.impl_trait_ref(id.owner_id).is_some()
|
||||
{
|
||||
trait_impls.push(id.owner_id.to_def_id())
|
||||
|
||||
@@ -136,7 +136,8 @@ fixed_size_enum! {
|
||||
( Field )
|
||||
( LifetimeParam )
|
||||
( GlobalAsm )
|
||||
( Impl )
|
||||
( Impl { of_trait: false } )
|
||||
( Impl { of_trait: true } )
|
||||
( Closure )
|
||||
( Generator )
|
||||
( Static(ast::Mutability::Not) )
|
||||
|
||||
@@ -203,7 +203,7 @@ impl<'hir> Map<'hir> {
|
||||
ItemKind::Use(..) => DefKind::Use,
|
||||
ItemKind::ForeignMod { .. } => DefKind::ForeignMod,
|
||||
ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
|
||||
ItemKind::Impl { .. } => DefKind::Impl,
|
||||
ItemKind::Impl(impl_) => DefKind::Impl { of_trait: impl_.of_trait.is_some() },
|
||||
},
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
ForeignItemKind::Fn(..) => DefKind::Fn,
|
||||
|
||||
@@ -19,29 +19,29 @@ pub trait PointerArithmetic: HasDataLayout {
|
||||
|
||||
#[inline(always)]
|
||||
fn max_size_of_val(&self) -> Size {
|
||||
Size::from_bytes(self.machine_isize_max())
|
||||
Size::from_bytes(self.target_isize_max())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn machine_usize_max(&self) -> u64 {
|
||||
fn target_usize_max(&self) -> u64 {
|
||||
self.pointer_size().unsigned_int_max().try_into().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn machine_isize_min(&self) -> i64 {
|
||||
fn target_isize_min(&self) -> i64 {
|
||||
self.pointer_size().signed_int_min().try_into().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn machine_isize_max(&self) -> i64 {
|
||||
fn target_isize_max(&self) -> i64 {
|
||||
self.pointer_size().signed_int_max().try_into().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn machine_usize_to_isize(&self, val: u64) -> i64 {
|
||||
fn target_usize_to_isize(&self, val: u64) -> i64 {
|
||||
let val = val as i64;
|
||||
// Now wrap-around into the machine_isize range.
|
||||
if val > self.machine_isize_max() {
|
||||
if val > self.target_isize_max() {
|
||||
// This can only happen if the ptr size is < 64, so we know max_usize_plus_1 fits into
|
||||
// i64.
|
||||
debug_assert!(self.pointer_size().bits() < 64);
|
||||
@@ -76,11 +76,11 @@ pub trait PointerArithmetic: HasDataLayout {
|
||||
let n = i.unsigned_abs();
|
||||
if i >= 0 {
|
||||
let (val, over) = self.overflowing_offset(val, n);
|
||||
(val, over || i > self.machine_isize_max())
|
||||
(val, over || i > self.target_isize_max())
|
||||
} else {
|
||||
let res = val.overflowing_sub(n);
|
||||
let (val, over) = self.truncate_to_ptr(res);
|
||||
(val, over || i < self.machine_isize_min())
|
||||
(val, over || i < self.target_isize_min())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ impl<'tcx> ConstValue<'tcx> {
|
||||
self.try_to_scalar_int()?.try_into().ok()
|
||||
}
|
||||
|
||||
pub fn try_to_machine_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_scalar_int()?.try_to_machine_usize(tcx).ok()
|
||||
pub fn try_to_target_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_scalar_int()?.try_to_target_usize(tcx).ok()
|
||||
}
|
||||
|
||||
pub fn try_to_bits_for_ty(
|
||||
@@ -97,8 +97,8 @@ impl<'tcx> ConstValue<'tcx> {
|
||||
ConstValue::Scalar(Scalar::from_u64(i))
|
||||
}
|
||||
|
||||
pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
|
||||
ConstValue::Scalar(Scalar::from_machine_usize(i, cx))
|
||||
pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
|
||||
ConstValue::Scalar(Scalar::from_target_usize(i, cx))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ impl<Prov> Scalar<Prov> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
|
||||
pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
|
||||
Self::from_uint(i, cx.data_layout().pointer_size)
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ impl<Prov> Scalar<Prov> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_machine_isize(i: i64, cx: &impl HasDataLayout) -> Self {
|
||||
pub fn from_target_isize(i: i64, cx: &impl HasDataLayout) -> Self {
|
||||
Self::from_int(i, cx.data_layout().pointer_size)
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
|
||||
|
||||
/// Converts the scalar to produce a machine-pointer-sized unsigned integer.
|
||||
/// Fails if the scalar is a pointer.
|
||||
pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
|
||||
pub fn to_target_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
|
||||
let b = self.to_uint(cx.data_layout().pointer_size)?;
|
||||
Ok(u64::try_from(b).unwrap())
|
||||
}
|
||||
@@ -469,7 +469,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
|
||||
|
||||
/// Converts the scalar to produce a machine-pointer-sized signed integer.
|
||||
/// Fails if the scalar is a pointer.
|
||||
pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
|
||||
pub fn to_target_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
|
||||
let b = self.to_int(cx.data_layout().pointer_size)?;
|
||||
Ok(i64::try_from(b).unwrap())
|
||||
}
|
||||
|
||||
@@ -2357,10 +2357,10 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
) -> Option<u64> {
|
||||
match self {
|
||||
Self::Ty(ct) => ct.try_eval_target_usize(tcx, param_env),
|
||||
Self::Val(val, _) => val.try_to_machine_usize(tcx),
|
||||
Self::Val(val, _) => val.try_to_target_usize(tcx),
|
||||
Self::Unevaluated(uneval, _) => {
|
||||
match tcx.const_eval_resolve(param_env, *uneval, None) {
|
||||
Ok(val) => val.try_to_machine_usize(tcx),
|
||||
Ok(val) => val.try_to_target_usize(tcx),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2143,12 +2143,12 @@ rustc_queries! {
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool {
|
||||
desc { "checking to see if `{}` permits being left uninit", key.value.ty }
|
||||
query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, ty::layout::LayoutError<'tcx>> {
|
||||
desc { "checking to see if `{}` permits being left uninit", key.value }
|
||||
}
|
||||
|
||||
query permits_zero_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool {
|
||||
desc { "checking to see if `{}` permits being left zeroed", key.value.ty }
|
||||
query permits_zero_init(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, ty::layout::LayoutError<'tcx>> {
|
||||
desc { "checking to see if `{}` permits being left zeroed", key.value }
|
||||
}
|
||||
|
||||
query compare_impl_const(
|
||||
|
||||
@@ -406,6 +406,7 @@ impl<'tcx> AdtDef<'tcx> {
|
||||
}
|
||||
|
||||
/// Return the index of `VariantDef` given a variant id.
|
||||
#[inline]
|
||||
pub fn variant_index_with_id(self, vid: DefId) -> VariantIdx {
|
||||
self.variants()
|
||||
.iter_enumerated()
|
||||
|
||||
@@ -206,7 +206,7 @@ impl<'tcx> Const<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
) -> Option<u64> {
|
||||
self.kind().eval(tcx, param_env).try_to_machine_usize(tcx)
|
||||
self.kind().eval(tcx, param_env).try_to_target_usize(tcx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -232,7 +232,7 @@ impl ScalarInt {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_machine_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
|
||||
pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
|
||||
Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
|
||||
}
|
||||
|
||||
|
||||
@@ -125,8 +125,8 @@ impl<'tcx> ConstKind<'tcx> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_value()?.try_to_machine_usize(tcx)
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_value()?.try_to_target_usize(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ impl<'tcx> ValTree<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_scalar_int().map(|s| s.try_to_machine_usize(tcx).ok()).flatten()
|
||||
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
|
||||
self.try_to_scalar_int().map(|s| s.try_to_target_usize(tcx).ok()).flatten()
|
||||
}
|
||||
|
||||
/// Get the values inside the ValTree as a slice of bytes. This only works for
|
||||
|
||||
@@ -125,7 +125,7 @@ impl FlagComputation {
|
||||
self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
|
||||
}
|
||||
|
||||
&ty::GeneratorWitnessMIR(_, ref substs) => {
|
||||
ty::GeneratorWitnessMIR(_, substs) => {
|
||||
let should_remove_further_specializable =
|
||||
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
|
||||
self.add_substs(substs);
|
||||
|
||||
@@ -159,7 +159,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
|
||||
match self {
|
||||
Self::ConstIsZero(c) => {
|
||||
let c = ty::EarlyBinder(c).subst(tcx, substs);
|
||||
let pred = match c.kind().try_to_machine_usize(tcx) {
|
||||
let pred = match c.kind().try_to_target_usize(tcx) {
|
||||
Some(0) => Self::True,
|
||||
Some(1..) => Self::False,
|
||||
None => Self::ConstIsZero(c),
|
||||
|
||||
@@ -191,7 +191,7 @@ fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedP
|
||||
|
||||
// If we can evaluate the array length before having a `ParamEnv`, then
|
||||
// we can simplify the predicate. This is an optimization.
|
||||
Array(ty, len) => match len.kind().try_to_machine_usize(tcx) {
|
||||
Array(ty, len) => match len.kind().try_to_target_usize(tcx) {
|
||||
Some(0) => InhabitedPredicate::True,
|
||||
Some(1..) => ty.inhabited_predicate(tcx),
|
||||
None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
|
||||
|
||||
@@ -2429,7 +2429,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
|
||||
if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
|
||||
let parent = self.parent(def_id);
|
||||
if let DefKind::Impl = self.def_kind(parent) {
|
||||
if let DefKind::Impl { .. } = self.def_kind(parent) {
|
||||
return Some(parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ use crate::traits::specialization_graph;
|
||||
use crate::traits::{self, ImplSource};
|
||||
use crate::ty::context::TyCtxtFeed;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::TyAndLayout;
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::GeneratorDiagnosticData;
|
||||
|
||||
@@ -167,7 +167,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
| DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Impl,
|
||||
| DefKind::Impl { .. },
|
||||
def_id,
|
||||
) => Some(def_id),
|
||||
Res::Err => None,
|
||||
|
||||
@@ -22,7 +22,7 @@ pub struct CopyProp;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CopyProp {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 4
|
||||
sess.mir_opt_level() >= 1
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||
@@ -96,7 +96,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
|
||||
fully_moved
|
||||
}
|
||||
|
||||
/// Utility to help performing subtitution of `*pattern` by `target`.
|
||||
/// Utility to help performing substitution of `*pattern` by `target`.
|
||||
struct Replacer<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fully_moved: BitSet<Local>,
|
||||
|
||||
@@ -6,7 +6,8 @@ use rustc_middle::mir::{
|
||||
BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
|
||||
};
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_middle::ty::{self, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
pub struct InstCombine;
|
||||
@@ -230,38 +231,41 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
|
||||
|
||||
// Check this is a foldable intrinsic before we query the layout of our generic parameter
|
||||
let Some(assert_panics) = intrinsic_assert_panics(intrinsic_name) else { return; };
|
||||
let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else { return; };
|
||||
if assert_panics(self.tcx, self.param_env.and(layout)) {
|
||||
match assert_panics(self.tcx, self.param_env.and(ty)) {
|
||||
// We don't know the layout, don't touch the assertion
|
||||
Err(_) => {}
|
||||
Ok(true) => {
|
||||
// If we know the assert panics, indicate to later opts that the call diverges
|
||||
*target = None;
|
||||
} else {
|
||||
}
|
||||
Ok(false) => {
|
||||
// If we know the assert does not panic, turn the call into a Goto
|
||||
terminator.kind = TerminatorKind::Goto { target: *target_block };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn intrinsic_assert_panics<'tcx>(
|
||||
intrinsic_name: Symbol,
|
||||
) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool> {
|
||||
) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<bool, LayoutError<'tcx>>> {
|
||||
fn inhabited_predicate<'tcx>(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
|
||||
) -> bool {
|
||||
let (_param_env, layout) = param_env_and_layout.into_parts();
|
||||
layout.abi.is_uninhabited()
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
Ok(tcx.layout_of(param_env_and_ty)?.abi.is_uninhabited())
|
||||
}
|
||||
fn zero_valid_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
|
||||
) -> bool {
|
||||
!tcx.permits_zero_init(param_env_and_layout)
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
Ok(!tcx.permits_zero_init(param_env_and_ty)?)
|
||||
}
|
||||
fn mem_uninitialized_valid_predicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
|
||||
) -> bool {
|
||||
!tcx.permits_uninit_init(param_env_and_layout)
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
Ok(!tcx.permits_uninit_init(param_env_and_ty)?)
|
||||
}
|
||||
|
||||
match intrinsic_name {
|
||||
|
||||
@@ -19,6 +19,33 @@ pub struct SsaLocals {
|
||||
copy_classes: IndexVec<Local, Local>,
|
||||
}
|
||||
|
||||
/// We often encounter MIR bodies with 1 or 2 basic blocks. In those cases, it's unnecessary to
|
||||
/// actually compute dominators, we can just compare block indices because bb0 is always the first
|
||||
/// block, and in any body all other blocks are always always dominated by bb0.
|
||||
struct SmallDominators {
|
||||
inner: Option<Dominators<BasicBlock>>,
|
||||
}
|
||||
|
||||
trait DomExt {
|
||||
fn dominates(self, _other: Self, dominators: &SmallDominators) -> bool;
|
||||
}
|
||||
|
||||
impl DomExt for Location {
|
||||
fn dominates(self, other: Location, dominators: &SmallDominators) -> bool {
|
||||
if self.block == other.block {
|
||||
self.statement_index <= other.statement_index
|
||||
} else {
|
||||
dominators.dominates(self.block, other.block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SmallDominators {
|
||||
fn dominates(&self, dom: BasicBlock, node: BasicBlock) -> bool {
|
||||
if let Some(inner) = &self.inner { inner.dominates(dom, node) } else { dom < node }
|
||||
}
|
||||
}
|
||||
|
||||
impl SsaLocals {
|
||||
pub fn new<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@@ -29,7 +56,9 @@ impl SsaLocals {
|
||||
let assignment_order = Vec::new();
|
||||
|
||||
let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
let dominators =
|
||||
if body.basic_blocks.len() > 2 { Some(body.basic_blocks.dominators()) } else { None };
|
||||
let dominators = SmallDominators { inner: dominators };
|
||||
let mut visitor = SsaVisitor { assignments, assignment_order, dominators };
|
||||
|
||||
for (local, decl) in body.local_decls.iter_enumerated() {
|
||||
@@ -41,9 +70,15 @@ impl SsaLocals {
|
||||
}
|
||||
}
|
||||
|
||||
if body.basic_blocks.len() > 2 {
|
||||
for (bb, data) in traversal::reverse_postorder(body) {
|
||||
visitor.visit_basic_block_data(bb, data);
|
||||
}
|
||||
} else {
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
visitor.visit_basic_block_data(bb, data);
|
||||
}
|
||||
}
|
||||
|
||||
for var_debug_info in &body.var_debug_info {
|
||||
visitor.visit_var_debug_info(var_debug_info);
|
||||
@@ -139,7 +174,7 @@ enum LocationExtended {
|
||||
}
|
||||
|
||||
struct SsaVisitor {
|
||||
dominators: Dominators<BasicBlock>,
|
||||
dominators: SmallDominators,
|
||||
assignments: IndexVec<Local, Set1<LocationExtended>>,
|
||||
assignment_order: Vec<Local>,
|
||||
}
|
||||
|
||||
@@ -1191,30 +1191,16 @@ impl<'v> RootCollector<'_, 'v> {
|
||||
fn process_item(&mut self, id: hir::ItemId) {
|
||||
match self.tcx.def_kind(id.owner_id) {
|
||||
DefKind::Enum | DefKind::Struct | DefKind::Union => {
|
||||
let item = self.tcx.hir().item(id);
|
||||
match item.kind {
|
||||
hir::ItemKind::Enum(_, ref generics)
|
||||
| hir::ItemKind::Struct(_, ref generics)
|
||||
| hir::ItemKind::Union(_, ref generics) => {
|
||||
if generics.params.is_empty() {
|
||||
if self.mode == MonoItemCollectionMode::Eager {
|
||||
debug!(
|
||||
"RootCollector: ADT drop-glue for {}",
|
||||
self.tcx.def_path_str(item.owner_id.to_def_id())
|
||||
);
|
||||
if self.mode == MonoItemCollectionMode::Eager
|
||||
&& self.tcx.generics_of(id.owner_id).count() == 0
|
||||
{
|
||||
debug!("RootCollector: ADT drop-glue for `{id:?}`",);
|
||||
|
||||
let ty = Instance::new(
|
||||
item.owner_id.to_def_id(),
|
||||
InternalSubsts::empty(),
|
||||
)
|
||||
.ty(self.tcx, ty::ParamEnv::reveal_all());
|
||||
let ty =
|
||||
self.tcx.bound_type_of(id.owner_id.to_def_id()).no_bound_vars().unwrap();
|
||||
visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
DefKind::GlobalAsm => {
|
||||
debug!(
|
||||
"RootCollector: ItemKind::GlobalAsm({})",
|
||||
@@ -1238,10 +1224,9 @@ impl<'v> RootCollector<'_, 'v> {
|
||||
collect_const_value(self.tcx, val, &mut self.output);
|
||||
}
|
||||
}
|
||||
DefKind::Impl => {
|
||||
DefKind::Impl { .. } => {
|
||||
if self.mode == MonoItemCollectionMode::Eager {
|
||||
let item = self.tcx.hir().item(id);
|
||||
create_mono_items_for_default_impls(self.tcx, item, self.output);
|
||||
create_mono_items_for_default_impls(self.tcx, id, self.output);
|
||||
}
|
||||
}
|
||||
DefKind::Fn => {
|
||||
@@ -1326,32 +1311,25 @@ fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
generics.requires_monomorphization(tcx)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx, output))]
|
||||
fn create_mono_items_for_default_impls<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
item: hir::ItemId,
|
||||
output: &mut MonoItems<'tcx>,
|
||||
) {
|
||||
match item.kind {
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
if matches!(impl_.polarity, hir::ImplPolarity::Negative(_)) {
|
||||
let polarity = tcx.impl_polarity(item.owner_id);
|
||||
if matches!(polarity, ty::ImplPolarity::Negative) {
|
||||
return;
|
||||
}
|
||||
|
||||
for param in impl_.generics.params {
|
||||
match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => {}
|
||||
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => {
|
||||
if tcx.generics_of(item.owner_id).own_requires_monomorphization() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"create_mono_items_for_default_impls(item={})",
|
||||
tcx.def_path_str(item.owner_id.to_def_id())
|
||||
);
|
||||
let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
|
||||
let trait_ref = trait_ref.subst_identity();
|
||||
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
@@ -1366,27 +1344,19 @@ fn create_mono_items_for_default_impls<'tcx>(
|
||||
continue;
|
||||
}
|
||||
|
||||
let substs =
|
||||
InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
|
||||
let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| match param.kind {
|
||||
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
GenericParamDefKind::Type { .. }
|
||||
| GenericParamDefKind::Const { .. } => {
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
trait_ref.substs[param.index as usize]
|
||||
}
|
||||
});
|
||||
let instance =
|
||||
ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
|
||||
let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, substs);
|
||||
|
||||
let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
|
||||
if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance)
|
||||
{
|
||||
if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) {
|
||||
output.push(mono_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Scans the miri alloc in order to find function calls, closures, and drop-glue.
|
||||
|
||||
@@ -172,7 +172,7 @@ fn mark_used_by_default_parameters<'tcx>(
|
||||
| DefKind::Field
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl => {
|
||||
| DefKind::Impl { .. } => {
|
||||
for param in &generics.params {
|
||||
debug!(?param, "(other)");
|
||||
if let ty::GenericParamDefKind::Lifetime = param.kind {
|
||||
|
||||
@@ -526,10 +526,8 @@ fn check_item<'tcx>(
|
||||
}
|
||||
}
|
||||
}
|
||||
DefKind::Impl => {
|
||||
let of_trait = tcx.impl_trait_ref(id.owner_id);
|
||||
|
||||
if of_trait.is_some() {
|
||||
DefKind::Impl { of_trait } => {
|
||||
if of_trait {
|
||||
worklist.push(id.owner_id.def_id);
|
||||
}
|
||||
|
||||
@@ -541,7 +539,7 @@ fn check_item<'tcx>(
|
||||
|
||||
// And we access the Map here to get HirId from LocalDefId
|
||||
for id in local_def_ids {
|
||||
if of_trait.is_some() || has_allow_dead_code_or_lang_attr(tcx, id) {
|
||||
if of_trait || has_allow_dead_code_or_lang_attr(tcx, id) {
|
||||
worklist.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||
|
||||
// Don't run unused pass for #[derive()]
|
||||
let parent = tcx.local_parent(local_def_id);
|
||||
if let DefKind::Impl = tcx.def_kind(parent)
|
||||
if let DefKind::Impl { .. } = tcx.def_kind(parent)
|
||||
&& tcx.has_attr(parent.to_def_id(), sym::automatically_derived)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -320,19 +320,19 @@ fn check_item<'tcx>(
|
||||
worklist.push(id.owner_id.def_id);
|
||||
}
|
||||
|
||||
if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
|
||||
if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl { of_trait: true }) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
||||
item.kind
|
||||
{
|
||||
if !effective_visibilities.is_reachable(item.owner_id.def_id) {
|
||||
worklist.extend(items.iter().map(|ii_ref| ii_ref.id.owner_id.def_id));
|
||||
if effective_visibilities.is_reachable(id.owner_id.def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
|
||||
let items = tcx.associated_item_def_ids(id.owner_id);
|
||||
worklist.extend(items.iter().map(|ii_ref| ii_ref.expect_local()));
|
||||
|
||||
let Some(trait_def_id) = tcx.trait_id_of_impl(id.owner_id.to_def_id()) else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
@@ -340,11 +340,8 @@ fn check_item<'tcx>(
|
||||
return;
|
||||
}
|
||||
|
||||
worklist.extend(
|
||||
tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()),
|
||||
);
|
||||
}
|
||||
}
|
||||
worklist
|
||||
.extend(tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()));
|
||||
}
|
||||
|
||||
fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
|
||||
@@ -593,7 +593,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
||||
| DefKind::InlineConst
|
||||
| DefKind::Field
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Closure
|
||||
| DefKind::Generator => (),
|
||||
}
|
||||
@@ -1997,7 +1997,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
|
||||
// Subitems of inherent impls have their own publicity.
|
||||
// A trait impl is public when both its type and its trait are public
|
||||
// Subitems of trait impls have inherited publicity.
|
||||
DefKind::Impl => {
|
||||
DefKind::Impl { .. } => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Impl(ref impl_) = item.kind {
|
||||
let impl_vis =
|
||||
|
||||
@@ -92,7 +92,7 @@ where
|
||||
let mut lock = self.cache.lock();
|
||||
// We may be overwriting another value. This is all right, since the dep-graph
|
||||
// will check that the fingerprint matches.
|
||||
lock.insert(key, (value.clone(), index));
|
||||
lock.insert(key, (value, index));
|
||||
value
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ where
|
||||
|
||||
#[inline]
|
||||
fn complete(&self, _key: (), value: V, index: DepNodeIndex) -> Self::Stored {
|
||||
*self.cache.lock() = Some((value.clone(), index));
|
||||
*self.cache.lock() = Some((value, index));
|
||||
value
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ where
|
||||
let mut lock = self.cache.get_shard_by_hash(key.index() as u64).lock();
|
||||
#[cfg(not(parallel_compiler))]
|
||||
let mut lock = self.cache.lock();
|
||||
lock.insert(key, (value.clone(), index));
|
||||
lock.insert(key, (value, index));
|
||||
value
|
||||
}
|
||||
|
||||
|
||||
@@ -987,7 +987,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::Closure
|
||||
| DefKind::Impl
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Generator,
|
||||
_,
|
||||
)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "rustc_save_analysis"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tracing = "0.1"
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
serde_json = "1"
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rls-data = "0.19"
|
||||
rls-span = "0.5"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
||||
use rls_data::config::Config;
|
||||
use rls_data::{
|
||||
self, Analysis, CompilationOptions, CratePreludeData, Def, DefKind, Impl, Import, MacroRef,
|
||||
Ref, RefKind, Relation,
|
||||
};
|
||||
use rls_span::{Column, Row};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Access {
|
||||
pub reachable: bool,
|
||||
pub public: bool,
|
||||
}
|
||||
|
||||
pub struct Dumper {
|
||||
result: Analysis,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl Dumper {
|
||||
pub fn new(config: Config) -> Dumper {
|
||||
Dumper { config: config.clone(), result: Analysis::new(config) }
|
||||
}
|
||||
|
||||
pub fn analysis(&self) -> &Analysis {
|
||||
&self.result
|
||||
}
|
||||
}
|
||||
|
||||
impl Dumper {
|
||||
pub fn crate_prelude(&mut self, data: CratePreludeData) {
|
||||
self.result.prelude = Some(data)
|
||||
}
|
||||
|
||||
pub fn compilation_opts(&mut self, data: CompilationOptions) {
|
||||
self.result.compilation = Some(data);
|
||||
}
|
||||
|
||||
pub fn _macro_use(&mut self, data: MacroRef) {
|
||||
if self.config.pub_only || self.config.reachable_only {
|
||||
return;
|
||||
}
|
||||
self.result.macro_refs.push(data);
|
||||
}
|
||||
|
||||
pub fn import(&mut self, access: &Access, import: Import) {
|
||||
if !access.public && self.config.pub_only || !access.reachable && self.config.reachable_only
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.result.imports.push(import);
|
||||
}
|
||||
|
||||
pub fn dump_ref(&mut self, data: Ref) {
|
||||
if self.config.pub_only || self.config.reachable_only {
|
||||
return;
|
||||
}
|
||||
self.result.refs.push(data);
|
||||
}
|
||||
|
||||
pub fn dump_def(&mut self, access: &Access, mut data: Def) {
|
||||
if !access.public && self.config.pub_only || !access.reachable && self.config.reachable_only
|
||||
{
|
||||
return;
|
||||
}
|
||||
if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value {
|
||||
// If the module is an out-of-line definition, then we'll make the
|
||||
// definition the first character in the module's file and turn
|
||||
// the declaration into a reference to it.
|
||||
let rf = Ref { kind: RefKind::Mod, span: data.span, ref_id: data.id };
|
||||
self.result.refs.push(rf);
|
||||
data.span = rls_data::SpanData {
|
||||
file_name: data.value.clone().into(),
|
||||
byte_start: 0,
|
||||
byte_end: 0,
|
||||
line_start: Row::new_one_indexed(1),
|
||||
line_end: Row::new_one_indexed(1),
|
||||
column_start: Column::new_one_indexed(1),
|
||||
column_end: Column::new_one_indexed(1),
|
||||
}
|
||||
}
|
||||
self.result.defs.push(data);
|
||||
}
|
||||
|
||||
pub fn dump_relation(&mut self, data: Relation) {
|
||||
self.result.relations.push(data);
|
||||
}
|
||||
|
||||
pub fn dump_impl(&mut self, data: Impl) {
|
||||
self.result.impls.push(data);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
use rustc_macros::Diagnostic;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(save_analysis_could_not_open)]
|
||||
pub(crate) struct CouldNotOpen<'a> {
|
||||
pub file_name: &'a Path,
|
||||
pub err: std::io::Error,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,931 +0,0 @@
|
||||
// A signature is a string representation of an item's type signature, excluding
|
||||
// any body. It also includes ids for any defs or refs in the signature. For
|
||||
// example:
|
||||
//
|
||||
// ```
|
||||
// fn foo(x: String) {
|
||||
// println!("{}", x);
|
||||
// }
|
||||
// ```
|
||||
// The signature string is something like "fn foo(x: String) {}" and the signature
|
||||
// will have defs for `foo` and `x` and a ref for `String`.
|
||||
//
|
||||
// All signature text should parse in the correct context (i.e., in a module or
|
||||
// impl, etc.). Clients may want to trim trailing `{}` or `;`. The text of a
|
||||
// signature is not guaranteed to be stable (it may improve or change as the
|
||||
// syntax changes, or whitespace or punctuation may change). It is also likely
|
||||
// not to be pretty - no attempt is made to prettify the text. It is recommended
|
||||
// that clients run the text through Rustfmt.
|
||||
//
|
||||
// This module generates Signatures for items by walking the AST and looking up
|
||||
// references.
|
||||
//
|
||||
// Signatures do not include visibility info. I'm not sure if this is a feature
|
||||
// or an omission (FIXME).
|
||||
//
|
||||
// FIXME where clauses need implementing, defs/refs in generics are mostly missing.
|
||||
|
||||
use crate::{id_from_def_id, SaveContext};
|
||||
|
||||
use rls_data::{SigElement, Signature};
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir_pretty::id_to_string;
|
||||
use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
|
||||
pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
item.make(0, None, scx).ok()
|
||||
}
|
||||
|
||||
pub fn foreign_item_signature(
|
||||
item: &hir::ForeignItem<'_>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
item.make(0, None, scx).ok()
|
||||
}
|
||||
|
||||
/// Signature for a struct or tuple field declaration.
|
||||
/// Does not include a trailing comma.
|
||||
pub fn field_signature(field: &hir::FieldDef<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
field.make(0, None, scx).ok()
|
||||
}
|
||||
|
||||
/// Does not include a trailing comma.
|
||||
pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
variant.make(0, None, scx).ok()
|
||||
}
|
||||
|
||||
pub fn method_signature(
|
||||
id: hir::OwnerId,
|
||||
ident: Ident,
|
||||
generics: &hir::Generics<'_>,
|
||||
m: &hir::FnSig<'_>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
make_method_signature(id, ident, generics, m, scx).ok()
|
||||
}
|
||||
|
||||
pub fn assoc_const_signature(
|
||||
id: hir::OwnerId,
|
||||
ident: Symbol,
|
||||
ty: &hir::Ty<'_>,
|
||||
default: Option<&hir::Expr<'_>>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
make_assoc_const_signature(id, ident, ty, default, scx).ok()
|
||||
}
|
||||
|
||||
pub fn assoc_type_signature(
|
||||
id: hir::OwnerId,
|
||||
ident: Ident,
|
||||
bounds: Option<hir::GenericBounds<'_>>,
|
||||
default: Option<&hir::Ty<'_>>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Option<Signature> {
|
||||
if !scx.config.signatures {
|
||||
return None;
|
||||
}
|
||||
make_assoc_type_signature(id, ident, bounds, default, scx).ok()
|
||||
}
|
||||
|
||||
type Result = std::result::Result<Signature, &'static str>;
|
||||
|
||||
trait Sig {
|
||||
type Parent;
|
||||
fn make(&self, offset: usize, id: Option<Self::Parent>, scx: &SaveContext<'_>) -> Result;
|
||||
}
|
||||
|
||||
fn extend_sig(
|
||||
mut sig: Signature,
|
||||
text: String,
|
||||
defs: Vec<SigElement>,
|
||||
refs: Vec<SigElement>,
|
||||
) -> Signature {
|
||||
sig.text = text;
|
||||
sig.defs.extend(defs.into_iter());
|
||||
sig.refs.extend(refs.into_iter());
|
||||
sig
|
||||
}
|
||||
|
||||
fn replace_text(mut sig: Signature, text: String) -> Signature {
|
||||
sig.text = text;
|
||||
sig
|
||||
}
|
||||
|
||||
fn merge_sigs(text: String, sigs: Vec<Signature>) -> Signature {
|
||||
let mut result = Signature { text, defs: vec![], refs: vec![] };
|
||||
|
||||
let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip();
|
||||
|
||||
result.defs.extend(defs.into_iter().flat_map(|ds| ds.into_iter()));
|
||||
result.refs.extend(refs.into_iter().flat_map(|rs| rs.into_iter()));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn text_sig(text: String) -> Signature {
|
||||
Signature { text, defs: vec![], refs: vec![] }
|
||||
}
|
||||
|
||||
impl<'hir> Sig for hir::Ty<'hir> {
|
||||
type Parent = hir::HirId;
|
||||
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
||||
let id = Some(self.hir_id);
|
||||
match self.kind {
|
||||
hir::TyKind::Slice(ref ty) => {
|
||||
let nested = ty.make(offset + 1, id, scx)?;
|
||||
let text = format!("[{}]", nested.text);
|
||||
Ok(replace_text(nested, text))
|
||||
}
|
||||
hir::TyKind::Ptr(ref mt) => {
|
||||
let prefix = match mt.mutbl {
|
||||
hir::Mutability::Mut => "*mut ",
|
||||
hir::Mutability::Not => "*const ",
|
||||
};
|
||||
let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
|
||||
let text = format!("{}{}", prefix, nested.text);
|
||||
Ok(replace_text(nested, text))
|
||||
}
|
||||
hir::TyKind::Ref(ref lifetime, ref mt) => {
|
||||
let mut prefix = "&".to_owned();
|
||||
prefix.push_str(&lifetime.ident.to_string());
|
||||
prefix.push(' ');
|
||||
if mt.mutbl.is_mut() {
|
||||
prefix.push_str("mut ");
|
||||
};
|
||||
|
||||
let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
|
||||
let text = format!("{}{}", prefix, nested.text);
|
||||
Ok(replace_text(nested, text))
|
||||
}
|
||||
hir::TyKind::Never => Ok(text_sig("!".to_owned())),
|
||||
hir::TyKind::Tup(ts) => {
|
||||
let mut text = "(".to_owned();
|
||||
let mut defs = vec![];
|
||||
let mut refs = vec![];
|
||||
for t in ts {
|
||||
let nested = t.make(offset + text.len(), id, scx)?;
|
||||
text.push_str(&nested.text);
|
||||
text.push(',');
|
||||
defs.extend(nested.defs.into_iter());
|
||||
refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
text.push(')');
|
||||
Ok(Signature { text, defs, refs })
|
||||
}
|
||||
hir::TyKind::BareFn(ref f) => {
|
||||
let mut text = String::new();
|
||||
if !f.generic_params.is_empty() {
|
||||
// FIXME defs, bounds on lifetimes
|
||||
text.push_str("for<");
|
||||
text.push_str(
|
||||
&f.generic_params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => {
|
||||
Some(param.name.ident().to_string())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
);
|
||||
text.push('>');
|
||||
}
|
||||
|
||||
if let hir::Unsafety::Unsafe = f.unsafety {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
text.push_str("fn(");
|
||||
|
||||
let mut defs = vec![];
|
||||
let mut refs = vec![];
|
||||
for i in f.decl.inputs {
|
||||
let nested = i.make(offset + text.len(), Some(i.hir_id), scx)?;
|
||||
text.push_str(&nested.text);
|
||||
text.push(',');
|
||||
defs.extend(nested.defs.into_iter());
|
||||
refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
text.push(')');
|
||||
if let hir::FnRetTy::Return(ref t) = f.decl.output {
|
||||
text.push_str(" -> ");
|
||||
let nested = t.make(offset + text.len(), None, scx)?;
|
||||
text.push_str(&nested.text);
|
||||
text.push(',');
|
||||
defs.extend(nested.defs.into_iter());
|
||||
refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
|
||||
Ok(Signature { text, defs, refs })
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.make(offset, id, scx),
|
||||
hir::TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref path)) => {
|
||||
let nested_ty = qself.make(offset + 1, id, scx)?;
|
||||
let prefix = format!(
|
||||
"<{} as {}>::",
|
||||
nested_ty.text,
|
||||
path_segment_to_string(&path.segments[0])
|
||||
);
|
||||
|
||||
let name = path_segment_to_string(path.segments.last().ok_or("Bad path")?);
|
||||
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
|
||||
let id = id_from_def_id(res.def_id());
|
||||
if path.segments.len() == 2 {
|
||||
let start = offset + prefix.len();
|
||||
let end = start + name.len();
|
||||
|
||||
Ok(Signature {
|
||||
text: prefix + &name,
|
||||
defs: vec![],
|
||||
refs: vec![SigElement { id, start, end }],
|
||||
})
|
||||
} else {
|
||||
let start = offset + prefix.len() + 5;
|
||||
let end = start + name.len();
|
||||
// FIXME should put the proper path in there, not ellipsis.
|
||||
Ok(Signature {
|
||||
text: prefix + "...::" + &name,
|
||||
defs: vec![],
|
||||
refs: vec![SigElement { id, start, end }],
|
||||
})
|
||||
}
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
|
||||
let nested_ty = ty.make(offset + 1, id, scx)?;
|
||||
let prefix = format!("<{}>::", nested_ty.text);
|
||||
|
||||
let name = path_segment_to_string(segment);
|
||||
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
|
||||
let id = id_from_def_id(res.def_id());
|
||||
|
||||
let start = offset + prefix.len();
|
||||
let end = start + name.len();
|
||||
Ok(Signature {
|
||||
text: prefix + &name,
|
||||
defs: vec![],
|
||||
refs: vec![SigElement { id, start, end }],
|
||||
})
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::LangItem(lang_item, _, _)) => {
|
||||
Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name())))
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, ..) => {
|
||||
// FIXME recurse into bounds
|
||||
let bounds: Vec<hir::GenericBound<'_>> = bounds
|
||||
.iter()
|
||||
.map(|hir::PolyTraitRef { bound_generic_params, trait_ref, span }| {
|
||||
hir::GenericBound::Trait(
|
||||
hir::PolyTraitRef {
|
||||
bound_generic_params,
|
||||
trait_ref: hir::TraitRef {
|
||||
path: trait_ref.path,
|
||||
hir_ref_id: trait_ref.hir_ref_id,
|
||||
},
|
||||
span: *span,
|
||||
},
|
||||
hir::TraitBoundModifier::None,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let nested = bounds_to_string(&bounds);
|
||||
Ok(text_sig(nested))
|
||||
}
|
||||
hir::TyKind::Array(ref ty, ref length) => {
|
||||
let nested_ty = ty.make(offset + 1, id, scx)?;
|
||||
let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " ");
|
||||
let text = format!("[{}; {}]", nested_ty.text, expr);
|
||||
Ok(replace_text(nested_ty, text))
|
||||
}
|
||||
hir::TyKind::OpaqueDef(item_id, _, _) => {
|
||||
let item = scx.tcx.hir().item(item_id);
|
||||
item.make(offset, Some(item_id.hir_id()), scx)
|
||||
}
|
||||
hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Sig for hir::Item<'hir> {
|
||||
type Parent = hir::HirId;
|
||||
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
||||
let id = Some(self.hir_id());
|
||||
|
||||
match self.kind {
|
||||
hir::ItemKind::Static(ref ty, m, ref body) => {
|
||||
let mut text = "static ".to_owned();
|
||||
if m.is_mut() {
|
||||
text.push_str("mut ");
|
||||
}
|
||||
let name = self.ident.to_string();
|
||||
let defs = vec![SigElement {
|
||||
id: id_from_def_id(self.owner_id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + name.len(),
|
||||
}];
|
||||
text.push_str(&name);
|
||||
text.push_str(": ");
|
||||
|
||||
let ty = ty.make(offset + text.len(), id, scx)?;
|
||||
text.push_str(&ty.text);
|
||||
|
||||
text.push_str(" = ");
|
||||
let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " ");
|
||||
text.push_str(&expr);
|
||||
|
||||
text.push(';');
|
||||
|
||||
Ok(extend_sig(ty, text, defs, vec![]))
|
||||
}
|
||||
hir::ItemKind::Const(ref ty, ref body) => {
|
||||
let mut text = "const ".to_owned();
|
||||
let name = self.ident.to_string();
|
||||
let defs = vec![SigElement {
|
||||
id: id_from_def_id(self.owner_id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + name.len(),
|
||||
}];
|
||||
text.push_str(&name);
|
||||
text.push_str(": ");
|
||||
|
||||
let ty = ty.make(offset + text.len(), id, scx)?;
|
||||
text.push_str(&ty.text);
|
||||
|
||||
text.push_str(" = ");
|
||||
let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " ");
|
||||
text.push_str(&expr);
|
||||
|
||||
text.push(';');
|
||||
|
||||
Ok(extend_sig(ty, text, defs, vec![]))
|
||||
}
|
||||
hir::ItemKind::Fn(hir::FnSig { ref decl, header, span: _ }, ref generics, _) => {
|
||||
let mut text = String::new();
|
||||
if let hir::Constness::Const = header.constness {
|
||||
text.push_str("const ");
|
||||
}
|
||||
if hir::IsAsync::Async == header.asyncness {
|
||||
text.push_str("async ");
|
||||
}
|
||||
if let hir::Unsafety::Unsafe = header.unsafety {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
text.push_str("fn ");
|
||||
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
|
||||
sig.text.push('(');
|
||||
for i in decl.inputs {
|
||||
// FIXME should descend into patterns to add defs.
|
||||
sig.text.push_str(": ");
|
||||
let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?;
|
||||
sig.text.push_str(&nested.text);
|
||||
sig.text.push(',');
|
||||
sig.defs.extend(nested.defs.into_iter());
|
||||
sig.refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
sig.text.push(')');
|
||||
|
||||
if let hir::FnRetTy::Return(ref t) = decl.output {
|
||||
sig.text.push_str(" -> ");
|
||||
let nested = t.make(offset + sig.text.len(), None, scx)?;
|
||||
sig.text.push_str(&nested.text);
|
||||
sig.defs.extend(nested.defs.into_iter());
|
||||
sig.refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
sig.text.push_str(" {}");
|
||||
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ItemKind::Macro(..) => {
|
||||
let mut text = "macro".to_owned();
|
||||
let name = self.ident.to_string();
|
||||
text.push_str(&name);
|
||||
text.push_str(&"! {}");
|
||||
|
||||
Ok(text_sig(text))
|
||||
}
|
||||
hir::ItemKind::Mod(ref _mod) => {
|
||||
let mut text = "mod ".to_owned();
|
||||
let name = self.ident.to_string();
|
||||
let defs = vec![SigElement {
|
||||
id: id_from_def_id(self.owner_id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + name.len(),
|
||||
}];
|
||||
text.push_str(&name);
|
||||
// Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one.
|
||||
text.push(';');
|
||||
|
||||
Ok(Signature { text, defs, refs: vec![] })
|
||||
}
|
||||
hir::ItemKind::TyAlias(ref ty, ref generics) => {
|
||||
let text = "type ".to_owned();
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
|
||||
sig.text.push_str(" = ");
|
||||
let ty = ty.make(offset + sig.text.len(), id, scx)?;
|
||||
sig.text.push_str(&ty.text);
|
||||
sig.text.push(';');
|
||||
|
||||
Ok(merge_sigs(sig.text.clone(), vec![sig, ty]))
|
||||
}
|
||||
hir::ItemKind::Enum(_, ref generics) => {
|
||||
let text = "enum ".to_owned();
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
sig.text.push_str(" {}");
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ItemKind::Struct(_, ref generics) => {
|
||||
let text = "struct ".to_owned();
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
sig.text.push_str(" {}");
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ItemKind::Union(_, ref generics) => {
|
||||
let text = "union ".to_owned();
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
sig.text.push_str(" {}");
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ItemKind::Trait(is_auto, unsafety, ref generics, bounds, _) => {
|
||||
let mut text = String::new();
|
||||
|
||||
if is_auto == hir::IsAuto::Yes {
|
||||
text.push_str("auto ");
|
||||
}
|
||||
|
||||
if let hir::Unsafety::Unsafe = unsafety {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
text.push_str("trait ");
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
|
||||
if !bounds.is_empty() {
|
||||
sig.text.push_str(": ");
|
||||
sig.text.push_str(&bounds_to_string(bounds));
|
||||
}
|
||||
// FIXME where clause
|
||||
sig.text.push_str(" {}");
|
||||
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ItemKind::TraitAlias(ref generics, bounds) => {
|
||||
let mut text = String::new();
|
||||
text.push_str("trait ");
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
|
||||
if !bounds.is_empty() {
|
||||
sig.text.push_str(" = ");
|
||||
sig.text.push_str(&bounds_to_string(bounds));
|
||||
}
|
||||
// FIXME where clause
|
||||
sig.text.push(';');
|
||||
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span: _,
|
||||
constness,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
items: _,
|
||||
}) => {
|
||||
let mut text = String::new();
|
||||
if let hir::Defaultness::Default { .. } = defaultness {
|
||||
text.push_str("default ");
|
||||
}
|
||||
if let hir::Unsafety::Unsafe = unsafety {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
text.push_str("impl");
|
||||
if let hir::Constness::Const = constness {
|
||||
text.push_str(" const");
|
||||
}
|
||||
|
||||
let generics_sig =
|
||||
generics.make(offset + text.len(), Some(self.owner_id.def_id), scx)?;
|
||||
text.push_str(&generics_sig.text);
|
||||
|
||||
text.push(' ');
|
||||
|
||||
let trait_sig = if let Some(ref t) = *of_trait {
|
||||
if let hir::ImplPolarity::Negative(_) = polarity {
|
||||
text.push('!');
|
||||
}
|
||||
let trait_sig = t.path.make(offset + text.len(), id, scx)?;
|
||||
text.push_str(&trait_sig.text);
|
||||
text.push_str(" for ");
|
||||
trait_sig
|
||||
} else {
|
||||
text_sig(String::new())
|
||||
};
|
||||
|
||||
let ty_sig = self_ty.make(offset + text.len(), id, scx)?;
|
||||
text.push_str(&ty_sig.text);
|
||||
|
||||
text.push_str(" {}");
|
||||
|
||||
Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig]))
|
||||
|
||||
// FIXME where clause
|
||||
}
|
||||
hir::ItemKind::ForeignMod { .. } => Err("extern mod"),
|
||||
hir::ItemKind::GlobalAsm(_) => Err("global asm"),
|
||||
hir::ItemKind::ExternCrate(_) => Err("extern crate"),
|
||||
hir::ItemKind::OpaqueTy(ref opaque) => {
|
||||
if opaque.in_trait {
|
||||
Err("opaque type in trait")
|
||||
} else {
|
||||
Err("opaque type")
|
||||
}
|
||||
}
|
||||
// FIXME should implement this (e.g., pub use).
|
||||
hir::ItemKind::Use(..) => Err("import"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Sig for hir::Path<'hir> {
|
||||
type Parent = hir::HirId;
|
||||
fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
||||
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
|
||||
|
||||
let (name, start, end) = match res {
|
||||
Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => {
|
||||
return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
|
||||
}
|
||||
Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
|
||||
let len = self.segments.len();
|
||||
if len < 2 {
|
||||
return Err("Bad path");
|
||||
}
|
||||
// FIXME: really we should descend into the generics here and add SigElements for
|
||||
// them.
|
||||
// FIXME: would be nice to have a def for the first path segment.
|
||||
let seg1 = path_segment_to_string(&self.segments[len - 2]);
|
||||
let seg2 = path_segment_to_string(&self.segments[len - 1]);
|
||||
let start = offset + seg1.len() + 2;
|
||||
(format!("{}::{}", seg1, seg2), start, start + seg2.len())
|
||||
}
|
||||
_ => {
|
||||
let name = path_segment_to_string(self.segments.last().ok_or("Bad path")?);
|
||||
let end = offset + name.len();
|
||||
(name, offset, end)
|
||||
}
|
||||
};
|
||||
|
||||
let id = id_from_def_id(res.def_id());
|
||||
Ok(Signature { text: name, defs: vec![], refs: vec![SigElement { id, start, end }] })
|
||||
}
|
||||
}
|
||||
|
||||
// This does not cover the where clause, which must be processed separately.
|
||||
impl<'hir> Sig for hir::Generics<'hir> {
|
||||
type Parent = LocalDefId;
|
||||
fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result {
|
||||
if self.params.is_empty() {
|
||||
return Ok(text_sig(String::new()));
|
||||
}
|
||||
|
||||
let mut text = "<".to_owned();
|
||||
|
||||
let mut defs = Vec::with_capacity(self.params.len());
|
||||
for param in self.params {
|
||||
let mut param_text = String::new();
|
||||
if let hir::GenericParamKind::Const { .. } = param.kind {
|
||||
param_text.push_str("const ");
|
||||
}
|
||||
param_text.push_str(param.name.ident().as_str());
|
||||
defs.push(SigElement {
|
||||
id: id_from_def_id(param.def_id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + param_text.as_str().len(),
|
||||
});
|
||||
if let hir::GenericParamKind::Const { ref ty, default } = param.kind {
|
||||
param_text.push_str(": ");
|
||||
param_text.push_str(&ty_to_string(&ty));
|
||||
if let Some(default) = default {
|
||||
param_text.push_str(" = ");
|
||||
param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
|
||||
}
|
||||
}
|
||||
text.push_str(¶m_text);
|
||||
text.push(',');
|
||||
}
|
||||
|
||||
text.push('>');
|
||||
Ok(Signature { text, defs, refs: vec![] })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Sig for hir::FieldDef<'hir> {
|
||||
type Parent = LocalDefId;
|
||||
fn make(&self, offset: usize, _parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result {
|
||||
let mut text = String::new();
|
||||
|
||||
text.push_str(&self.ident.to_string());
|
||||
let defs = Some(SigElement {
|
||||
id: id_from_def_id(self.def_id.to_def_id()),
|
||||
start: offset,
|
||||
end: offset + text.len(),
|
||||
});
|
||||
text.push_str(": ");
|
||||
|
||||
let mut ty_sig = self.ty.make(offset + text.len(), Some(self.hir_id), scx)?;
|
||||
text.push_str(&ty_sig.text);
|
||||
ty_sig.text = text;
|
||||
ty_sig.defs.extend(defs.into_iter());
|
||||
Ok(ty_sig)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Sig for hir::Variant<'hir> {
|
||||
type Parent = LocalDefId;
|
||||
fn make(&self, offset: usize, parent_id: Option<LocalDefId>, scx: &SaveContext<'_>) -> Result {
|
||||
let mut text = self.ident.to_string();
|
||||
match self.data {
|
||||
hir::VariantData::Struct(fields, r) => {
|
||||
let id = parent_id.ok_or("Missing id for Variant's parent")?;
|
||||
let name_def = SigElement {
|
||||
id: id_from_def_id(id.to_def_id()),
|
||||
start: offset,
|
||||
end: offset + text.len(),
|
||||
};
|
||||
text.push_str(" { ");
|
||||
let mut defs = vec![name_def];
|
||||
let mut refs = vec![];
|
||||
if r {
|
||||
text.push_str("/* parse error */ ");
|
||||
} else {
|
||||
for f in fields {
|
||||
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
|
||||
text.push_str(&field_sig.text);
|
||||
text.push_str(", ");
|
||||
defs.extend(field_sig.defs.into_iter());
|
||||
refs.extend(field_sig.refs.into_iter());
|
||||
}
|
||||
}
|
||||
text.push('}');
|
||||
Ok(Signature { text, defs, refs })
|
||||
}
|
||||
hir::VariantData::Tuple(fields, _, def_id) => {
|
||||
let name_def = SigElement {
|
||||
id: id_from_def_id(def_id.to_def_id()),
|
||||
start: offset,
|
||||
end: offset + text.len(),
|
||||
};
|
||||
text.push('(');
|
||||
let mut defs = vec![name_def];
|
||||
let mut refs = vec![];
|
||||
for f in fields {
|
||||
let field_sig = f.make(offset + text.len(), Some(def_id), scx)?;
|
||||
text.push_str(&field_sig.text);
|
||||
text.push_str(", ");
|
||||
defs.extend(field_sig.defs.into_iter());
|
||||
refs.extend(field_sig.refs.into_iter());
|
||||
}
|
||||
text.push(')');
|
||||
Ok(Signature { text, defs, refs })
|
||||
}
|
||||
hir::VariantData::Unit(_, def_id) => {
|
||||
let name_def = SigElement {
|
||||
id: id_from_def_id(def_id.to_def_id()),
|
||||
start: offset,
|
||||
end: offset + text.len(),
|
||||
};
|
||||
Ok(Signature { text, defs: vec![name_def], refs: vec![] })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Sig for hir::ForeignItem<'hir> {
|
||||
type Parent = hir::HirId;
|
||||
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
||||
let id = Some(self.hir_id());
|
||||
match self.kind {
|
||||
hir::ForeignItemKind::Fn(decl, _, ref generics) => {
|
||||
let mut text = String::new();
|
||||
text.push_str("fn ");
|
||||
|
||||
let mut sig =
|
||||
name_and_generics(text, offset, generics, self.owner_id, self.ident, scx)?;
|
||||
|
||||
sig.text.push('(');
|
||||
for i in decl.inputs {
|
||||
sig.text.push_str(": ");
|
||||
let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?;
|
||||
sig.text.push_str(&nested.text);
|
||||
sig.text.push(',');
|
||||
sig.defs.extend(nested.defs.into_iter());
|
||||
sig.refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
sig.text.push(')');
|
||||
|
||||
if let hir::FnRetTy::Return(ref t) = decl.output {
|
||||
sig.text.push_str(" -> ");
|
||||
let nested = t.make(offset + sig.text.len(), None, scx)?;
|
||||
sig.text.push_str(&nested.text);
|
||||
sig.defs.extend(nested.defs.into_iter());
|
||||
sig.refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
sig.text.push(';');
|
||||
|
||||
Ok(sig)
|
||||
}
|
||||
hir::ForeignItemKind::Static(ref ty, m) => {
|
||||
let mut text = "static ".to_owned();
|
||||
text.push_str(m.prefix_str());
|
||||
|
||||
let name = self.ident.to_string();
|
||||
let defs = vec![SigElement {
|
||||
id: id_from_def_id(self.owner_id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + name.len(),
|
||||
}];
|
||||
text.push_str(&name);
|
||||
text.push_str(": ");
|
||||
|
||||
let ty_sig = ty.make(offset + text.len(), id, scx)?;
|
||||
text.push(';');
|
||||
|
||||
Ok(extend_sig(ty_sig, text, defs, vec![]))
|
||||
}
|
||||
hir::ForeignItemKind::Type => {
|
||||
let mut text = "type ".to_owned();
|
||||
let name = self.ident.to_string();
|
||||
let defs = vec![SigElement {
|
||||
id: id_from_def_id(self.owner_id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + name.len(),
|
||||
}];
|
||||
text.push_str(&name);
|
||||
text.push(';');
|
||||
|
||||
Ok(Signature { text, defs, refs: vec![] })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name_and_generics(
|
||||
mut text: String,
|
||||
offset: usize,
|
||||
generics: &hir::Generics<'_>,
|
||||
id: hir::OwnerId,
|
||||
name: Ident,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Result {
|
||||
let name = name.to_string();
|
||||
let def = SigElement {
|
||||
id: id_from_def_id(id.to_def_id()),
|
||||
start: offset + text.len(),
|
||||
end: offset + text.len() + name.len(),
|
||||
};
|
||||
text.push_str(&name);
|
||||
let generics: Signature = generics.make(offset + text.len(), Some(id.def_id), scx)?;
|
||||
// FIXME where clause
|
||||
let text = format!("{}{}", text, generics.text);
|
||||
Ok(extend_sig(generics, text, vec![def], vec![]))
|
||||
}
|
||||
|
||||
fn make_assoc_type_signature(
|
||||
id: hir::OwnerId,
|
||||
ident: Ident,
|
||||
bounds: Option<hir::GenericBounds<'_>>,
|
||||
default: Option<&hir::Ty<'_>>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Result {
|
||||
let mut text = "type ".to_owned();
|
||||
let name = ident.to_string();
|
||||
let mut defs = vec![SigElement {
|
||||
id: id_from_def_id(id.to_def_id()),
|
||||
start: text.len(),
|
||||
end: text.len() + name.len(),
|
||||
}];
|
||||
let mut refs = vec![];
|
||||
text.push_str(&name);
|
||||
if let Some(bounds) = bounds {
|
||||
text.push_str(": ");
|
||||
// FIXME should descend into bounds
|
||||
text.push_str(&bounds_to_string(bounds));
|
||||
}
|
||||
if let Some(default) = default {
|
||||
text.push_str(" = ");
|
||||
let ty_sig = default.make(text.len(), Some(id.into()), scx)?;
|
||||
text.push_str(&ty_sig.text);
|
||||
defs.extend(ty_sig.defs.into_iter());
|
||||
refs.extend(ty_sig.refs.into_iter());
|
||||
}
|
||||
text.push(';');
|
||||
Ok(Signature { text, defs, refs })
|
||||
}
|
||||
|
||||
fn make_assoc_const_signature(
|
||||
id: hir::OwnerId,
|
||||
ident: Symbol,
|
||||
ty: &hir::Ty<'_>,
|
||||
default: Option<&hir::Expr<'_>>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Result {
|
||||
let mut text = "const ".to_owned();
|
||||
let name = ident.to_string();
|
||||
let mut defs = vec![SigElement {
|
||||
id: id_from_def_id(id.to_def_id()),
|
||||
start: text.len(),
|
||||
end: text.len() + name.len(),
|
||||
}];
|
||||
let mut refs = vec![];
|
||||
text.push_str(&name);
|
||||
text.push_str(": ");
|
||||
|
||||
let ty_sig = ty.make(text.len(), Some(id.into()), scx)?;
|
||||
text.push_str(&ty_sig.text);
|
||||
defs.extend(ty_sig.defs.into_iter());
|
||||
refs.extend(ty_sig.refs.into_iter());
|
||||
|
||||
if let Some(default) = default {
|
||||
text.push_str(" = ");
|
||||
text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
|
||||
}
|
||||
text.push(';');
|
||||
Ok(Signature { text, defs, refs })
|
||||
}
|
||||
|
||||
fn make_method_signature(
|
||||
id: hir::OwnerId,
|
||||
ident: Ident,
|
||||
generics: &hir::Generics<'_>,
|
||||
m: &hir::FnSig<'_>,
|
||||
scx: &SaveContext<'_>,
|
||||
) -> Result {
|
||||
// FIXME code dup with function signature
|
||||
let mut text = String::new();
|
||||
if let hir::Constness::Const = m.header.constness {
|
||||
text.push_str("const ");
|
||||
}
|
||||
if hir::IsAsync::Async == m.header.asyncness {
|
||||
text.push_str("async ");
|
||||
}
|
||||
if let hir::Unsafety::Unsafe = m.header.unsafety {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
text.push_str("fn ");
|
||||
|
||||
let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
|
||||
|
||||
sig.text.push('(');
|
||||
for i in m.decl.inputs {
|
||||
sig.text.push_str(": ");
|
||||
let nested = i.make(sig.text.len(), Some(i.hir_id), scx)?;
|
||||
sig.text.push_str(&nested.text);
|
||||
sig.text.push(',');
|
||||
sig.defs.extend(nested.defs.into_iter());
|
||||
sig.refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
sig.text.push(')');
|
||||
|
||||
if let hir::FnRetTy::Return(ref t) = m.decl.output {
|
||||
sig.text.push_str(" -> ");
|
||||
let nested = t.make(sig.text.len(), None, scx)?;
|
||||
sig.text.push_str(&nested.text);
|
||||
sig.defs.extend(nested.defs.into_iter());
|
||||
sig.refs.extend(nested.refs.into_iter());
|
||||
}
|
||||
sig.text.push_str(" {}");
|
||||
|
||||
Ok(sig)
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
use crate::generated_code;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_lexer::{tokenize, TokenKind};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SpanUtils<'a> {
|
||||
pub sess: &'a Session,
|
||||
}
|
||||
|
||||
impl<'a> SpanUtils<'a> {
|
||||
pub fn new(sess: &'a Session) -> SpanUtils<'a> {
|
||||
SpanUtils { sess }
|
||||
}
|
||||
|
||||
pub fn make_filename_string(&self, file: &SourceFile) -> String {
|
||||
match &file.name {
|
||||
FileName::Real(RealFileName::LocalPath(path)) => {
|
||||
if path.is_absolute() {
|
||||
self.sess.source_map().path_mapping().map_prefix(path).0.display().to_string()
|
||||
} else {
|
||||
self.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.remapped_path_if_available()
|
||||
.join(&path)
|
||||
.display()
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
filename => filename.prefer_remapped().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snippet(&self, span: Span) -> String {
|
||||
match self.sess.source_map().span_to_snippet(span) {
|
||||
Ok(s) => s,
|
||||
Err(_) => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the span of `*` token withing the larger `span`.
|
||||
pub fn sub_span_of_star(&self, mut span: Span) -> Option<Span> {
|
||||
let begin = self.sess.source_map().lookup_byte_offset(span.lo());
|
||||
let end = self.sess.source_map().lookup_byte_offset(span.hi());
|
||||
// Make the range zero-length if the span is invalid.
|
||||
if begin.sf.start_pos != end.sf.start_pos {
|
||||
span = span.shrink_to_lo();
|
||||
}
|
||||
|
||||
let sf = Lrc::clone(&begin.sf);
|
||||
|
||||
self.sess.source_map().ensure_source_file_source_present(Lrc::clone(&sf));
|
||||
let src =
|
||||
sf.src.clone().or_else(|| sf.external_src.borrow().get_source().map(Lrc::clone))?;
|
||||
let to_index = |pos: BytePos| -> usize { (pos - sf.start_pos).0 as usize };
|
||||
let text = &src[to_index(span.lo())..to_index(span.hi())];
|
||||
let start_pos = {
|
||||
let mut pos = 0;
|
||||
tokenize(text)
|
||||
.map(|token| {
|
||||
let start = pos;
|
||||
pos += token.len;
|
||||
(start, token)
|
||||
})
|
||||
.find(|(_pos, token)| token.kind == TokenKind::Star)?
|
||||
.0
|
||||
};
|
||||
let lo = span.lo() + BytePos(start_pos as u32);
|
||||
let hi = lo + BytePos(1);
|
||||
Some(span.with_lo(lo).with_hi(hi))
|
||||
}
|
||||
|
||||
/// Return true if the span is generated code, and
|
||||
/// it is not a subspan of the root callsite.
|
||||
///
|
||||
/// Used to filter out spans of minimal value,
|
||||
/// such as references to macro internal variables.
|
||||
pub fn filter_generated(&self, span: Span) -> bool {
|
||||
if generated_code(span) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//If the span comes from a fake source_file, filter it.
|
||||
!self.sess.source_map().lookup_char_pos(span.lo()).file.is_real_file()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! filter {
|
||||
($util: expr, $parent: expr) => {
|
||||
if $util.filter_generated($parent) {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1629,9 +1629,6 @@ options! {
|
||||
saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"make float->int casts UB-free: numbers outside the integer type's range are clipped to \
|
||||
the max/min integer respectively, and NaN is mapped to 0 (default: yes)"),
|
||||
save_analysis: bool = (false, parse_bool, [UNTRACKED],
|
||||
"write syntax and type analysis (in JSON format) information, in \
|
||||
addition to normal output (default: no)"),
|
||||
self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
||||
parse_switch_with_opt_path, [UNTRACKED],
|
||||
"run the self profiler and output the raw event data"),
|
||||
|
||||
@@ -547,7 +547,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
response.value.certainty == Certainty::Yes
|
||||
&& response.has_no_inference_or_external_constraints()
|
||||
}) {
|
||||
return Ok(response.clone());
|
||||
return Ok(*response);
|
||||
}
|
||||
|
||||
let certainty = candidates.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
|
||||
|
||||
@@ -1628,7 +1628,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
// Eventually I'll need to implement param-env-aware
|
||||
// `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
if self.can_sub(param_env, error, implication).is_ok() {
|
||||
if self.can_sub(param_env, error, implication) {
|
||||
debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
let impl_self_ty = impl_trait_ref.self_ty();
|
||||
|
||||
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
|
||||
if self.can_eq(param_env, trait_self_ty, impl_self_ty) {
|
||||
self_match_impls.push((def_id, impl_substs));
|
||||
|
||||
if iter::zip(
|
||||
@@ -261,7 +261,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
|
||||
if let ty::Array(aty, len) = self_ty.kind() {
|
||||
flags.push((sym::_Self, Some("[]".to_string())));
|
||||
let len = len.kind().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
|
||||
let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
|
||||
flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
|
||||
if let Some(n) = len {
|
||||
flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
|
||||
|
||||
@@ -748,10 +748,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let real_ty = real_trait_pred.self_ty();
|
||||
// We `erase_late_bound_regions` here because `make_subregion` does not handle
|
||||
// `ReLateBound`, and we don't particularly care about the regions.
|
||||
if self
|
||||
.can_eq(obligation.param_env, self.tcx.erase_late_bound_regions(real_ty), arg_ty)
|
||||
.is_err()
|
||||
{
|
||||
if !self.can_eq(
|
||||
obligation.param_env,
|
||||
self.tcx.erase_late_bound_regions(real_ty),
|
||||
arg_ty,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3690,7 +3691,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let Some((span, (assoc, ty))) = entry else { continue; };
|
||||
if primary_spans.is_empty() || type_diffs.iter().any(|diff| {
|
||||
let Sorts(expected_found) = diff else { return false; };
|
||||
self.can_eq(param_env, expected_found.found, ty).is_ok()
|
||||
self.can_eq(param_env, expected_found.found, ty)
|
||||
}) {
|
||||
// FIXME: this doesn't quite work for `Iterator::collect`
|
||||
// because we have `Vec<i32>` and `()`, but we'd want `i32`
|
||||
@@ -3717,10 +3718,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let ty_str = with_forced_trimmed_paths!(self.ty_to_string(ty));
|
||||
|
||||
let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc));
|
||||
if self.can_eq(param_env, ty, *prev_ty).is_err() {
|
||||
if !self.can_eq(param_env, ty, *prev_ty) {
|
||||
if type_diffs.iter().any(|diff| {
|
||||
let Sorts(expected_found) = diff else { return false; };
|
||||
self.can_eq(param_env, expected_found.found, ty).is_ok()
|
||||
self.can_eq(param_env, expected_found.found, ty)
|
||||
}) {
|
||||
primary_spans.push(span);
|
||||
}
|
||||
@@ -3868,7 +3869,7 @@ fn hint_missing_borrow<'tcx>(
|
||||
let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
|
||||
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
|
||||
|
||||
if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
|
||||
if infcx.can_eq(param_env, found_ty, expected_ty) {
|
||||
// FIXME: This could handle more exotic cases like mutability mismatches too!
|
||||
if found_refs.len() < expected_refs.len()
|
||||
&& found_refs[..] == expected_refs[expected_refs.len() - found_refs.len()..]
|
||||
|
||||
@@ -599,7 +599,7 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
return false;
|
||||
}
|
||||
|
||||
contains_illegal_self_type_reference(tcx, trait_def_id, pred.clone())
|
||||
contains_illegal_self_type_reference(tcx, trait_def_id, pred)
|
||||
}) {
|
||||
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user