Merge from rustc
This commit is contained in:
commit
14155e95b1
166 changed files with 1875 additions and 1960 deletions
36
.github/workflows/ci.yml
vendored
36
.github/workflows/ci.yml
vendored
|
|
@ -38,6 +38,7 @@ jobs:
|
|||
env:
|
||||
CI_JOB_NAME: "${{ matrix.name }}"
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||
HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
|
||||
SCCACHE_BUCKET: rust-lang-ci-sccache2
|
||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||
CACHE_DOMAIN: ci-caches.rust-lang.org
|
||||
|
|
@ -143,6 +144,17 @@ jobs:
|
|||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to github
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "${{ env.DOC_ARTIFACT_NAME }}"
|
||||
path: obj/artifacts/doc
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
env:
|
||||
|
|
@ -156,6 +168,7 @@ jobs:
|
|||
env:
|
||||
CI_JOB_NAME: "${{ matrix.name }}"
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||
HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
|
||||
SCCACHE_BUCKET: rust-lang-ci-sccache2
|
||||
DEPLOY_BUCKET: rust-lang-ci2
|
||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||
|
|
@ -557,6 +570,17 @@ jobs:
|
|||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to github
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "${{ env.DOC_ARTIFACT_NAME }}"
|
||||
path: obj/artifacts/doc
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
env:
|
||||
|
|
@ -571,6 +595,7 @@ jobs:
|
|||
DIST_TRY_BUILD: 1
|
||||
CI_JOB_NAME: "${{ matrix.name }}"
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||
HEAD_SHA: "${{ github.event.pull_request.head.sha || github.sha }}"
|
||||
SCCACHE_BUCKET: rust-lang-ci-sccache2
|
||||
DEPLOY_BUCKET: rust-lang-ci2
|
||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||
|
|
@ -672,6 +697,17 @@ jobs:
|
|||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to github
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: "${{ env.DOC_ARTIFACT_NAME }}"
|
||||
path: obj/artifacts/doc
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
self.const_uint(self.type_u64(), i)
|
||||
}
|
||||
|
||||
fn const_u128(&self, i: u128) -> RValue<'gcc> {
|
||||
self.const_uint_big(self.type_u128(), i)
|
||||
}
|
||||
|
||||
fn const_usize(&self, i: u64) -> RValue<'gcc> {
|
||||
let bit_size = self.data_layout().pointer_size.bits();
|
||||
if bit_size < 64 {
|
||||
|
|
@ -254,7 +258,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
// SIMD builtins require a constant value.
|
||||
self.bitcast_if_needed(value, typ)
|
||||
}
|
||||
|
||||
|
||||
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
|
||||
self.context.new_array_access(None, base_addr, self.const_usize(offset.bytes())).get_address(None)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
self.const_uint(self.type_i64(), i)
|
||||
}
|
||||
|
||||
fn const_u128(&self, i: u128) -> &'ll Value {
|
||||
self.const_uint_big(self.type_i128(), i)
|
||||
}
|
||||
|
||||
fn const_usize(&self, i: u64) -> &'ll Value {
|
||||
let bit_size = self.data_layout().pointer_size.bits();
|
||||
if bit_size < 64 {
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
|
|||
return existing_di_node;
|
||||
}
|
||||
|
||||
debug!("type_di_node: {:?}", t);
|
||||
debug!("type_di_node: {:?} kind: {:?}", t, t.kind());
|
||||
|
||||
let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
|
||||
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
||||
|
|
|
|||
|
|
@ -412,13 +412,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
|
|||
enum_type_and_layout.size.bits(),
|
||||
enum_type_and_layout.align.abi.bits() as u32,
|
||||
Size::ZERO.bits(),
|
||||
discr_value.opt_single_val().map(|value| {
|
||||
// NOTE(eddyb) do *NOT* remove this assert, until
|
||||
// we pass the full 128-bit value to LLVM, otherwise
|
||||
// truncation will be silent and remain undetected.
|
||||
assert_eq!(value as u64 as u128, value);
|
||||
cx.const_u64(value as u64)
|
||||
}),
|
||||
discr_value.opt_single_val().map(|value| cx.const_u128(value)),
|
||||
DIFlags::FlagZero,
|
||||
variant_member_info.variant_struct_type_di_node,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_errors::{ErrorGuaranteed, Handler};
|
||||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::find_native_static_library;
|
||||
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
|
||||
|
|
@ -2682,6 +2682,30 @@ fn add_upstream_native_libraries(
|
|||
}
|
||||
}
|
||||
|
||||
// Rehome lib paths (which exclude the library file name) that point into the sysroot lib directory
|
||||
// to be relative to the sysroot directory, which may be a relative path specified by the user.
|
||||
//
|
||||
// If the sysroot is a relative path, and the sysroot libs are specified as an absolute path, the
|
||||
// linker command line can be non-deterministic due to the paths including the current working
|
||||
// directory. The linker command line needs to be deterministic since it appears inside the PDB
|
||||
// file generated by the MSVC linker. See https://github.com/rust-lang/rust/issues/112586.
|
||||
//
|
||||
// The returned path will always have `fix_windows_verbatim_for_gcc()` applied to it.
|
||||
fn rehome_sysroot_lib_dir<'a>(sess: &'a Session, lib_dir: &Path) -> PathBuf {
|
||||
let sysroot_lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
|
||||
let canonical_sysroot_lib_path =
|
||||
{ try_canonicalize(&sysroot_lib_path).unwrap_or_else(|_| sysroot_lib_path.clone()) };
|
||||
|
||||
let canonical_lib_dir = try_canonicalize(lib_dir).unwrap_or_else(|_| lib_dir.to_path_buf());
|
||||
if canonical_lib_dir == canonical_sysroot_lib_path {
|
||||
// This path, returned by `target_filesearch().get_lib_path()`, has
|
||||
// already had `fix_windows_verbatim_for_gcc()` applied if needed.
|
||||
sysroot_lib_path
|
||||
} else {
|
||||
fix_windows_verbatim_for_gcc(&lib_dir)
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the static "rlib" versions of all crates to the command line.
|
||||
// There's a bit of magic which happens here specifically related to LTO,
|
||||
// namely that we remove upstream object files.
|
||||
|
|
@ -2713,7 +2737,13 @@ fn add_static_crate<'a>(
|
|||
let cratepath = &src.rlib.as_ref().unwrap().0;
|
||||
|
||||
let mut link_upstream = |path: &Path| {
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(path));
|
||||
let rlib_path = if let Some(dir) = path.parent() {
|
||||
let file_name = path.file_name().expect("rlib path has no file name path component");
|
||||
rehome_sysroot_lib_dir(sess, &dir).join(file_name)
|
||||
} else {
|
||||
fix_windows_verbatim_for_gcc(path)
|
||||
};
|
||||
cmd.link_rlib(&rlib_path);
|
||||
};
|
||||
|
||||
if !are_upstream_rust_objects_already_included(sess)
|
||||
|
|
@ -2782,7 +2812,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
|
|||
// what its name is
|
||||
let parent = cratepath.parent();
|
||||
if let Some(dir) = parent {
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
|
||||
cmd.include_path(&rehome_sysroot_lib_dir(sess, dir));
|
||||
}
|
||||
let stem = cratepath.file_stem().unwrap().to_str().unwrap();
|
||||
// Convert library file-stem into a cc -l argument.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
|
|||
fn const_i32(&self, i: i32) -> Self::Value;
|
||||
fn const_u32(&self, i: u32) -> Self::Value;
|
||||
fn const_u64(&self, i: u64) -> Self::Value;
|
||||
fn const_u128(&self, i: u128) -> Self::Value;
|
||||
fn const_usize(&self, i: u64) -> Self::Value;
|
||||
fn const_u8(&self, i: u8) -> Self::Value;
|
||||
fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;
|
||||
|
|
|
|||
|
|
@ -781,8 +781,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
Ok(Some(ImplSource::Closure(data))) => {
|
||||
if !tcx.is_const_fn_raw(data.closure_def_id) {
|
||||
// Closure: Fn{Once|Mut}
|
||||
Ok(Some(ImplSource::Builtin(_)))
|
||||
if poly_trait_pred.self_ty().skip_binder().is_closure()
|
||||
&& tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
|
||||
{
|
||||
let ty::Closure(closure_def_id, substs) =
|
||||
*poly_trait_pred.self_ty().no_bound_vars().unwrap().kind()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
if !tcx.is_const_fn_raw(closure_def_id) {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ impl Qualif for NeedsNonConstDrop {
|
|||
|
||||
if !matches!(
|
||||
impl_src,
|
||||
ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
||||
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
||||
) {
|
||||
// If our const destruct candidate is not ConstDestruct or implied by the param env,
|
||||
// then it's bad
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
|||
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
|
||||
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
|
||||
|
||||
ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
|
||||
ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
|
||||
ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
|
||||
ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_session::parse::{feature_err, ParseSess};
|
|||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Span, SyntaxContext};
|
||||
use rustc_span::Span;
|
||||
|
||||
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
|
||||
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
|
||||
|
|
@ -72,7 +72,7 @@ pub(super) fn parse(
|
|||
// `SyntaxContext::root()` from a foreign crate will
|
||||
// have the edition of that crate (which we manually
|
||||
// retrieve via the `edition` parameter).
|
||||
if span.ctxt() == SyntaxContext::root() {
|
||||
if span.ctxt().is_root() {
|
||||
edition
|
||||
} else {
|
||||
span.edition()
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ language_item_table! {
|
|||
EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
|
||||
|
||||
OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
|
||||
// Experimental language item for Miri
|
||||
PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1);
|
||||
|
||||
PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1);
|
||||
|
||||
|
|
|
|||
124
compiler/rustc_hir_analysis/src/astconv/lint.rs
Normal file
124
compiler/rustc_hir_analysis/src/astconv/lint.rs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
use rustc_ast::TraitObjectSyntax;
|
||||
use rustc_errors::{Diagnostic, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||
|
||||
use super::AstConv;
|
||||
|
||||
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
/// Make sure that we are in the condition to suggest the blanket implementation.
|
||||
pub(super) fn maybe_lint_blanket_trait_impl(
|
||||
&self,
|
||||
self_ty: &hir::Ty<'_>,
|
||||
diag: &mut Diagnostic,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||
if let hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
|
||||
}),
|
||||
..
|
||||
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
|
||||
{
|
||||
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
||||
return;
|
||||
}
|
||||
let of_trait_span = of_trait_ref.path.span;
|
||||
// make sure that we are not calling unwrap to abort during the compilation
|
||||
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
|
||||
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
|
||||
// check if the trait has generics, to make a correct suggestion
|
||||
let param_name = generics.params.next_type_param_name(None);
|
||||
|
||||
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
|
||||
(span, format!(", {}: {}", param_name, impl_trait_name))
|
||||
} else {
|
||||
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
|
||||
};
|
||||
diag.multipart_suggestion(
|
||||
format!("alternatively use a blanket \
|
||||
implementation to implement `{of_trait_name}` for \
|
||||
all types that also implement `{impl_trait_name}`"),
|
||||
vec![
|
||||
(self_ty.span, param_name),
|
||||
add_generic_sugg,
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
|
||||
let tcx = self.tcx();
|
||||
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||
self_ty.kind
|
||||
{
|
||||
let needs_bracket = in_path
|
||||
&& !tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_prev_source(self_ty.span)
|
||||
.ok()
|
||||
.is_some_and(|s| s.trim_end().ends_with('<'));
|
||||
|
||||
let is_global = poly_trait_ref.trait_ref.path.is_global();
|
||||
|
||||
let mut sugg = Vec::from_iter([(
|
||||
self_ty.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{}dyn {}",
|
||||
if needs_bracket { "<" } else { "" },
|
||||
if is_global { "(" } else { "" },
|
||||
),
|
||||
)]);
|
||||
|
||||
if is_global || needs_bracket {
|
||||
sugg.push((
|
||||
self_ty.span.shrink_to_hi(),
|
||||
format!(
|
||||
"{}{}",
|
||||
if is_global { ")" } else { "" },
|
||||
if needs_bracket { ">" } else { "" },
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if self_ty.span.edition().rust_2021() {
|
||||
let msg = "trait objects must include the `dyn` keyword";
|
||||
let label = "add `dyn` keyword before this trait";
|
||||
let mut diag =
|
||||
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
|
||||
if self_ty.span.can_be_used_for_suggestions() {
|
||||
diag.multipart_suggestion_verbose(
|
||||
label,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// check if the impl trait that we are considering is a impl of a local trait
|
||||
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
} else {
|
||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||
tcx.struct_span_lint_hir(
|
||||
BARE_TRAIT_OBJECTS,
|
||||
self_ty.hir_id,
|
||||
self_ty.span,
|
||||
msg,
|
||||
|lint| {
|
||||
lint.multipart_suggestion_verbose(
|
||||
"use `dyn`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
|
||||
lint
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
mod errors;
|
||||
pub mod generics;
|
||||
mod lint;
|
||||
|
||||
use crate::astconv::errors::prohibit_assoc_ty_binding;
|
||||
use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
|
||||
|
|
@ -19,7 +20,7 @@ use rustc_ast::TraitObjectSyntax;
|
|||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
|
||||
MultiSpan, StashKey,
|
||||
MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||
|
|
@ -33,14 +34,12 @@ use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
|||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{DynKind, ToPredicate};
|
||||
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
use rustc_span::{sym, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::traits::error_reporting::{
|
||||
report_object_safety_error, suggestions::NextTypeParamName,
|
||||
};
|
||||
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
|
||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, astconv_object_safety_violations, NormalizeExt, ObligationCtxt,
|
||||
|
|
@ -1458,7 +1457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
item_segment: &hir::PathSegment<'_>,
|
||||
) -> Ty<'tcx> {
|
||||
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
|
||||
self.tcx().at(span).type_of(did).subst(self.tcx(), substs)
|
||||
let ty = self.tcx().at(span).type_of(did);
|
||||
|
||||
if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
|
||||
&& ty.skip_binder().has_opaque_types()
|
||||
{
|
||||
// Type aliases referring to types that contain opaque types (but aren't just directly
|
||||
// referencing a single opaque type) get encoded as a type alias that normalization will
|
||||
// then actually instantiate the where bounds of.
|
||||
let alias_ty = self.tcx().mk_alias_ty(did, substs);
|
||||
self.tcx().mk_alias(ty::Weak, alias_ty)
|
||||
} else {
|
||||
ty.subst(self.tcx(), substs)
|
||||
}
|
||||
}
|
||||
|
||||
fn conv_object_ty_poly_trait_ref(
|
||||
|
|
@ -3703,115 +3714,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
Some(r)
|
||||
}
|
||||
|
||||
/// Make sure that we are in the condition to suggest the blanket implementation.
|
||||
fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
|
||||
let tcx = self.tcx();
|
||||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||
if let hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, ..
|
||||
}),
|
||||
..
|
||||
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
|
||||
{
|
||||
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
|
||||
return;
|
||||
}
|
||||
let of_trait_span = of_trait_ref.path.span;
|
||||
// make sure that we are not calling unwrap to abort during the compilation
|
||||
let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
|
||||
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
|
||||
// check if the trait has generics, to make a correct suggestion
|
||||
let param_name = generics.params.next_type_param_name(None);
|
||||
|
||||
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
|
||||
(span, format!(", {}: {}", param_name, impl_trait_name))
|
||||
} else {
|
||||
(generics.span, format!("<{}: {}>", param_name, impl_trait_name))
|
||||
};
|
||||
diag.multipart_suggestion(
|
||||
format!("alternatively use a blanket \
|
||||
implementation to implement `{of_trait_name}` for \
|
||||
all types that also implement `{impl_trait_name}`"),
|
||||
vec![
|
||||
(self_ty.span, param_name),
|
||||
add_generic_sugg,
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
|
||||
let tcx = self.tcx();
|
||||
if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
|
||||
self_ty.kind
|
||||
{
|
||||
let needs_bracket = in_path
|
||||
&& !tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_prev_source(self_ty.span)
|
||||
.ok()
|
||||
.is_some_and(|s| s.trim_end().ends_with('<'));
|
||||
|
||||
let is_global = poly_trait_ref.trait_ref.path.is_global();
|
||||
|
||||
let mut sugg = Vec::from_iter([(
|
||||
self_ty.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{}dyn {}",
|
||||
if needs_bracket { "<" } else { "" },
|
||||
if is_global { "(" } else { "" },
|
||||
),
|
||||
)]);
|
||||
|
||||
if is_global || needs_bracket {
|
||||
sugg.push((
|
||||
self_ty.span.shrink_to_hi(),
|
||||
format!(
|
||||
"{}{}",
|
||||
if is_global { ")" } else { "" },
|
||||
if needs_bracket { ">" } else { "" },
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if self_ty.span.edition().rust_2021() {
|
||||
let msg = "trait objects must include the `dyn` keyword";
|
||||
let label = "add `dyn` keyword before this trait";
|
||||
let mut diag =
|
||||
rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
|
||||
if self_ty.span.can_be_used_for_suggestions() {
|
||||
diag.multipart_suggestion_verbose(
|
||||
label,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// check if the impl trait that we are considering is a impl of a local trait
|
||||
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
|
||||
diag.stash(self_ty.span, StashKey::TraitMissingMethod);
|
||||
} else {
|
||||
let msg = "trait objects without an explicit `dyn` are deprecated";
|
||||
tcx.struct_span_lint_hir(
|
||||
BARE_TRAIT_OBJECTS,
|
||||
self_ty.hir_id,
|
||||
self_ty.span,
|
||||
msg,
|
||||
|lint| {
|
||||
lint.multipart_suggestion_verbose(
|
||||
"use `dyn`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
self.maybe_lint_blanket_trait_impl(&self_ty, lint);
|
||||
lint
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,10 +217,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
|||
check_item_fn(tcx, def_id, item.ident, item.span, sig.decl);
|
||||
}
|
||||
hir::ItemKind::Static(ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, false);
|
||||
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
|
||||
}
|
||||
hir::ItemKind::Const(ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, false);
|
||||
check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid);
|
||||
}
|
||||
hir::ItemKind::Struct(_, ast_generics) => {
|
||||
check_type_defn(tcx, item, false);
|
||||
|
|
@ -242,6 +242,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
|||
}
|
||||
// `ForeignItem`s are handled separately.
|
||||
hir::ItemKind::ForeignMod { .. } => {}
|
||||
hir::ItemKind::TyAlias(hir_ty, ..) => {
|
||||
if tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
|
||||
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
|
||||
check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -258,7 +264,9 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
|
|||
hir::ForeignItemKind::Fn(decl, ..) => {
|
||||
check_item_fn(tcx, def_id, item.ident, item.span, decl)
|
||||
}
|
||||
hir::ForeignItemKind::Static(ty, ..) => check_item_type(tcx, def_id, ty.span, true),
|
||||
hir::ForeignItemKind::Static(ty, ..) => {
|
||||
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
|
||||
}
|
||||
hir::ForeignItemKind::Type => (),
|
||||
}
|
||||
}
|
||||
|
|
@ -1100,20 +1108,32 @@ fn check_item_fn(
|
|||
})
|
||||
}
|
||||
|
||||
fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_foreign_ty: bool) {
|
||||
enum UnsizedHandling {
|
||||
Forbid,
|
||||
Allow,
|
||||
AllowIfForeignTail,
|
||||
}
|
||||
|
||||
fn check_item_type(
|
||||
tcx: TyCtxt<'_>,
|
||||
item_id: LocalDefId,
|
||||
ty_span: Span,
|
||||
unsized_handling: UnsizedHandling,
|
||||
) {
|
||||
debug!("check_item_type: {:?}", item_id);
|
||||
|
||||
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
|
||||
let ty = tcx.type_of(item_id).subst_identity();
|
||||
let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
|
||||
|
||||
let mut forbid_unsized = true;
|
||||
if allow_foreign_ty {
|
||||
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
|
||||
if let ty::Foreign(_) = tail.kind() {
|
||||
forbid_unsized = false;
|
||||
let forbid_unsized = match unsized_handling {
|
||||
UnsizedHandling::Forbid => true,
|
||||
UnsizedHandling::Allow => false,
|
||||
UnsizedHandling::AllowIfForeignTail => {
|
||||
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
|
||||
!matches!(tail.kind(), ty::Foreign(_))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
|
||||
if forbid_unsized {
|
||||
|
|
|
|||
|
|
@ -200,35 +200,32 @@ fn do_orphan_check_impl<'tcx>(
|
|||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
|
||||
// trait Id { type This: ?Sized; }
|
||||
// impl<T: ?Sized> Id for T {
|
||||
// type This = T;
|
||||
// }
|
||||
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
|
||||
ty::Alias(AliasKind::Projection, _) => (
|
||||
LocalImpl::Disallow { problematic_kind: "associated type" },
|
||||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
|
||||
// ```
|
||||
// struct S<T>(T);
|
||||
// impl<T: ?Sized> S<T> {
|
||||
// type This = T;
|
||||
// }
|
||||
// impl<T: ?Sized> AutoTrait for S<T>::This {}
|
||||
// ```
|
||||
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
|
||||
ty::Alias(AliasKind::Inherent, _) => (
|
||||
LocalImpl::Disallow { problematic_kind: "associated type" },
|
||||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
|
||||
// type Opaque = impl Trait;
|
||||
// impl AutoTrait for Opaque {}
|
||||
ty::Alias(AliasKind::Opaque, _) => (
|
||||
LocalImpl::Disallow { problematic_kind: "opaque type" },
|
||||
NonlocalImpl::DisallowOther,
|
||||
),
|
||||
ty::Alias(kind, _) => {
|
||||
let problematic_kind = match kind {
|
||||
// trait Id { type This: ?Sized; }
|
||||
// impl<T: ?Sized> Id for T {
|
||||
// type This = T;
|
||||
// }
|
||||
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
|
||||
AliasKind::Projection => "associated type",
|
||||
// type Foo = (impl Sized, bool)
|
||||
// impl AutoTrait for Foo {}
|
||||
AliasKind::Weak => "type alias",
|
||||
// type Opaque = impl Trait;
|
||||
// impl AutoTrait for Opaque {}
|
||||
AliasKind::Opaque => "opaque type",
|
||||
// ```
|
||||
// struct S<T>(T);
|
||||
// impl<T: ?Sized> S<T> {
|
||||
// type This = T;
|
||||
// }
|
||||
// impl<T: ?Sized> AutoTrait for S<T>::This {}
|
||||
// ```
|
||||
// FIXME(inherent_associated_types): The example code above currently leads to a cycle
|
||||
AliasKind::Inherent => "associated type",
|
||||
};
|
||||
(LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
|
||||
}
|
||||
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ pub(super) fn explicit_item_bounds(
|
|||
};
|
||||
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
||||
}
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
|
||||
_ => bug!("item_bounds called on {:?}", def_id),
|
||||
};
|
||||
ty::EarlyBinder::bind(bounds)
|
||||
|
|
|
|||
|
|
@ -128,7 +128,9 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
ref item => bug!("Unexpected TraitItem {:?}", item),
|
||||
},
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => vec![ty],
|
||||
hir::ItemKind::TyAlias(ty, _)
|
||||
| hir::ItemKind::Static(ty, _, _)
|
||||
| hir::ItemKind::Const(ty, _) => vec![ty],
|
||||
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
|
||||
Some(t) => t
|
||||
.path
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
|
||||
);
|
||||
|
||||
let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
|
||||
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: self.tcx.def_span(expr_def_id),
|
||||
});
|
||||
|
|
@ -143,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Create a type variable (for now) to represent the closure kind.
|
||||
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||
None => self.next_ty_var(TypeVariableOrigin {
|
||||
None => self.next_root_ty_var(TypeVariableOrigin {
|
||||
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
|
|
|
|||
|
|
@ -189,6 +189,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub fn errors_reported_since_creation(&self) -> bool {
|
||||
self.tcx.sess.err_count() > self.err_count_on_creation
|
||||
}
|
||||
|
||||
pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
|
||||
self.tcx.mk_ty_var(self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -2375,6 +2375,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
||||
format!("the associated type `{}`", p)
|
||||
}
|
||||
ty::AliasKind::Weak => format!("the type alias `{}`", p),
|
||||
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1465,8 +1465,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
|||
let hir::ItemKind::TyAlias(ty, type_alias_generics) = &item.kind else {
|
||||
return
|
||||
};
|
||||
if let hir::TyKind::OpaqueDef(..) = ty.kind {
|
||||
// Bounds are respected for `type X = impl Trait`
|
||||
if cx.tcx.type_of(item.owner_id.def_id).skip_binder().has_opaque_types() {
|
||||
// Bounds are respected for `type X = impl Trait` and `type X = (impl Trait, Y);`
|
||||
return;
|
||||
}
|
||||
if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
|
||||
|
|
|
|||
|
|
@ -1255,7 +1255,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Param(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Infer(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Error(_)
|
||||
|
|
|
|||
|
|
@ -82,15 +82,40 @@ impl CanonicalVarValues<'_> {
|
|||
}
|
||||
|
||||
pub fn is_identity_modulo_regions(&self) -> bool {
|
||||
self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
|
||||
ty::GenericArgKind::Lifetime(_) => true,
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
|
||||
let mut var = ty::BoundVar::from_u32(0);
|
||||
for arg in self.var_values {
|
||||
match arg.unpack() {
|
||||
ty::GenericArgKind::Lifetime(r) => {
|
||||
if let ty::ReLateBound(ty::INNERMOST, br) = *r
|
||||
&& var == br.var
|
||||
{
|
||||
var = var + 1;
|
||||
} else {
|
||||
// It's ok if this region var isn't unique
|
||||
}
|
||||
},
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
if let ty::Bound(ty::INNERMOST, bt) = *ty.kind()
|
||||
&& var == bt.var
|
||||
{
|
||||
var = var + 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind()
|
||||
&& var == bc
|
||||
{
|
||||
var = var + 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_middle::hir;
|
|||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::MirSpanview;
|
||||
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
|
||||
use rustc_span::{BytePos, Pos, Span};
|
||||
|
||||
use std::cmp;
|
||||
use std::io::{self, Write};
|
||||
|
|
@ -327,7 +327,7 @@ fn compute_block_span(data: &BasicBlockData<'_>, body_span: Span) -> Span {
|
|||
let mut span = data.terminator().source_info.span;
|
||||
for statement_span in data.statements.iter().map(|statement| statement.source_info.span) {
|
||||
// Only combine Spans from the root context, and within the function's body_span.
|
||||
if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) {
|
||||
if statement_span.ctxt().is_root() && body_span.contains(statement_span) {
|
||||
span = span.to(statement_span);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1903,6 +1903,16 @@ rustc_queries! {
|
|||
desc { "normalizing `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: invoke `normalize` instead.
|
||||
query normalize_weak_ty(
|
||||
goal: CanonicalProjectionGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
|
||||
NoSolution,
|
||||
> {
|
||||
desc { "normalizing `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: invoke `normalize` instead.
|
||||
query normalize_inherent_projection_ty(
|
||||
goal: CanonicalProjectionGoal<'tcx>
|
||||
|
|
|
|||
|
|
@ -448,6 +448,9 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
|
||||
/// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy`
|
||||
ConstParam(Ty<'tcx>),
|
||||
|
||||
/// Obligations emitted during the normalization of a weak type alias.
|
||||
TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId),
|
||||
}
|
||||
|
||||
/// The 'location' at which we try to perform HIR-based wf checking.
|
||||
|
|
@ -643,12 +646,6 @@ pub enum ImplSource<'tcx, N> {
|
|||
/// ImplSource identifying a particular impl.
|
||||
UserDefined(ImplSourceUserDefinedData<'tcx, N>),
|
||||
|
||||
/// ImplSource for auto trait implementations.
|
||||
/// This carries the information and nested obligations with regards
|
||||
/// to an auto implementation for a trait `Trait`. The nested obligations
|
||||
/// ensure the trait implementation holds for all the constituent types.
|
||||
AutoImpl(ImplSourceAutoImplData<N>),
|
||||
|
||||
/// Successful resolution to an obligation provided by the caller
|
||||
/// for some type parameter. The `Vec<N>` represents the
|
||||
/// obligations incurred from normalizing the where-clause (if
|
||||
|
|
@ -656,84 +653,46 @@ pub enum ImplSource<'tcx, N> {
|
|||
Param(Vec<N>, ty::BoundConstness),
|
||||
|
||||
/// Virtual calls through an object.
|
||||
Object(ImplSourceObjectData<'tcx, N>),
|
||||
Object(ImplSourceObjectData<N>),
|
||||
|
||||
/// Successful resolution for a builtin trait.
|
||||
Builtin(ImplSourceBuiltinData<N>),
|
||||
Builtin(Vec<N>),
|
||||
|
||||
/// ImplSource for trait upcasting coercion
|
||||
TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
|
||||
|
||||
/// ImplSource automatically generated for a closure. The `DefId` is the ID
|
||||
/// of the closure expression. This is an `ImplSource::UserDefined` in spirit, but the
|
||||
/// impl is generated by the compiler and does not appear in the source.
|
||||
Closure(ImplSourceClosureData<'tcx, N>),
|
||||
|
||||
/// Same as above, but for a function pointer type with the given signature.
|
||||
FnPointer(ImplSourceFnPointerData<'tcx, N>),
|
||||
|
||||
/// ImplSource automatically generated for a generator.
|
||||
Generator(ImplSourceGeneratorData<'tcx, N>),
|
||||
|
||||
/// ImplSource automatically generated for a generator backing an async future.
|
||||
Future(ImplSourceFutureData<'tcx, N>),
|
||||
TraitUpcasting(ImplSourceTraitUpcastingData<N>),
|
||||
|
||||
/// ImplSource for a trait alias.
|
||||
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
|
||||
|
||||
/// ImplSource for a `const Drop` implementation.
|
||||
ConstDestruct(ImplSourceConstDestructData<N>),
|
||||
}
|
||||
|
||||
impl<'tcx, N> ImplSource<'tcx, N> {
|
||||
pub fn nested_obligations(self) -> Vec<N> {
|
||||
match self {
|
||||
ImplSource::UserDefined(i) => i.nested,
|
||||
ImplSource::Param(n, _) => n,
|
||||
ImplSource::Builtin(i) => i.nested,
|
||||
ImplSource::AutoImpl(d) => d.nested,
|
||||
ImplSource::Closure(c) => c.nested,
|
||||
ImplSource::Generator(c) => c.nested,
|
||||
ImplSource::Future(c) => c.nested,
|
||||
ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
|
||||
ImplSource::Object(d) => d.nested,
|
||||
ImplSource::FnPointer(d) => d.nested,
|
||||
ImplSource::TraitAlias(d) => d.nested,
|
||||
ImplSource::TraitUpcasting(d) => d.nested,
|
||||
ImplSource::ConstDestruct(i) => i.nested,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_nested_obligations(&self) -> &[N] {
|
||||
match self {
|
||||
ImplSource::UserDefined(i) => &i.nested,
|
||||
ImplSource::Param(n, _) => n,
|
||||
ImplSource::Builtin(i) => &i.nested,
|
||||
ImplSource::AutoImpl(d) => &d.nested,
|
||||
ImplSource::Closure(c) => &c.nested,
|
||||
ImplSource::Generator(c) => &c.nested,
|
||||
ImplSource::Future(c) => &c.nested,
|
||||
ImplSource::Param(n, _) | ImplSource::Builtin(n) => &n,
|
||||
ImplSource::Object(d) => &d.nested,
|
||||
ImplSource::FnPointer(d) => &d.nested,
|
||||
ImplSource::TraitAlias(d) => &d.nested,
|
||||
ImplSource::TraitUpcasting(d) => &d.nested,
|
||||
ImplSource::ConstDestruct(i) => &i.nested,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
|
||||
match self {
|
||||
ImplSource::UserDefined(i) => &mut i.nested,
|
||||
ImplSource::Param(n, _) => n,
|
||||
ImplSource::Builtin(i) => &mut i.nested,
|
||||
ImplSource::AutoImpl(d) => &mut d.nested,
|
||||
ImplSource::Closure(c) => &mut c.nested,
|
||||
ImplSource::Generator(c) => &mut c.nested,
|
||||
ImplSource::Future(c) => &mut c.nested,
|
||||
ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
|
||||
ImplSource::Object(d) => &mut d.nested,
|
||||
ImplSource::FnPointer(d) => &mut d.nested,
|
||||
ImplSource::TraitAlias(d) => &mut d.nested,
|
||||
ImplSource::TraitUpcasting(d) => &mut d.nested,
|
||||
ImplSource::ConstDestruct(i) => &mut i.nested,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -748,37 +707,12 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
|||
nested: i.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
|
||||
ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData {
|
||||
nested: i.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()),
|
||||
ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
|
||||
upcast_trait_ref: o.upcast_trait_ref,
|
||||
upcast_trait_def_id: o.upcast_trait_def_id,
|
||||
vtable_base: o.vtable_base,
|
||||
nested: o.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData {
|
||||
trait_def_id: d.trait_def_id,
|
||||
nested: d.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData {
|
||||
closure_def_id: c.closure_def_id,
|
||||
substs: c.substs,
|
||||
nested: c.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData {
|
||||
generator_def_id: c.generator_def_id,
|
||||
substs: c.substs,
|
||||
nested: c.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::Future(c) => ImplSource::Future(ImplSourceFutureData {
|
||||
generator_def_id: c.generator_def_id,
|
||||
substs: c.substs,
|
||||
nested: c.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData {
|
||||
fn_ty: p.fn_ty,
|
||||
nested: p.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
|
||||
alias_def_id: d.alias_def_id,
|
||||
substs: d.substs,
|
||||
|
|
@ -786,16 +720,10 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
|||
}),
|
||||
ImplSource::TraitUpcasting(d) => {
|
||||
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
|
||||
upcast_trait_ref: d.upcast_trait_ref,
|
||||
vtable_vptr_slot: d.vtable_vptr_slot,
|
||||
nested: d.nested.into_iter().map(f).collect(),
|
||||
})
|
||||
}
|
||||
ImplSource::ConstDestruct(i) => {
|
||||
ImplSource::ConstDestruct(ImplSourceConstDestructData {
|
||||
nested: i.nested.into_iter().map(f).collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -820,47 +748,7 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceGeneratorData<'tcx, N> {
|
||||
pub generator_def_id: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
/// Nested obligations. This can be non-empty if the generator
|
||||
/// signature contains associated types.
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceFutureData<'tcx, N> {
|
||||
pub generator_def_id: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
/// Nested obligations. This can be non-empty if the generator
|
||||
/// signature contains associated types.
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceClosureData<'tcx, N> {
|
||||
pub closure_def_id: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
/// Nested obligations. This can be non-empty if the closure
|
||||
/// signature contains associated types.
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceAutoImplData<N> {
|
||||
pub trait_def_id: DefId,
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceTraitUpcastingData<'tcx, N> {
|
||||
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
|
||||
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
||||
pub struct ImplSourceTraitUpcastingData<N> {
|
||||
/// The vtable is formed by concatenating together the method lists of
|
||||
/// the base object trait and all supertraits, pointers to supertrait vtable will
|
||||
/// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
|
||||
|
|
@ -870,17 +758,11 @@ pub struct ImplSourceTraitUpcastingData<'tcx, N> {
|
|||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceBuiltinData<N> {
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceObjectData<'tcx, N> {
|
||||
pub struct ImplSourceObjectData<N> {
|
||||
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
|
||||
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
pub upcast_trait_def_id: DefId,
|
||||
|
||||
/// The vtable is formed by concatenating together the method lists of
|
||||
/// the base object trait and all supertraits, pointers to supertrait vtable will
|
||||
|
|
@ -891,19 +773,6 @@ pub struct ImplSourceObjectData<'tcx, N> {
|
|||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceFnPointerData<'tcx, N> {
|
||||
pub fn_ty: Ty<'tcx>,
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceConstDestructData<N> {
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceTraitAliasData<'tcx, N> {
|
||||
|
|
|
|||
|
|
@ -9,15 +9,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
|
|||
match *self {
|
||||
super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v),
|
||||
|
||||
super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t),
|
||||
|
||||
super::ImplSource::Closure(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Generator(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Future(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d),
|
||||
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
|
|
@ -25,13 +17,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
|
|||
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
|
||||
}
|
||||
|
||||
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,78 +34,26 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx,
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceGeneratorData<'tcx, N> {
|
||||
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ImplSourceGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
|
||||
self.generator_def_id, self.substs, self.nested
|
||||
"ImplSourceTraitUpcastingData(vtable_vptr_slot={:?}, nested={:?})",
|
||||
self.vtable_vptr_slot, self.nested
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFutureData<'tcx, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ImplSourceFutureData(generator_def_id={:?}, substs={:?}, nested={:?})",
|
||||
self.generator_def_id, self.substs, self.nested
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceClosureData<'tcx, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ImplSourceClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
|
||||
self.closure_def_id, self.substs, self.nested
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ImplSourceBuiltinData(nested={:?})", self.nested)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
|
||||
self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ImplSourceAutoImplData(trait_def_id={:?}, nested={:?})",
|
||||
self.trait_def_id, self.nested
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<'tcx, N> {
|
||||
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ImplSourceObjectData(upcast={:?}, vtable_base={}, nested={:?})",
|
||||
self.upcast_trait_ref, self.vtable_base, self.nested
|
||||
self.upcast_trait_def_id, self.vtable_base, self.nested
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFnPointerData<'tcx, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ImplSourceFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
|
|
@ -127,9 +63,3 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ImplSourceConstDestructData(nested={:?})", self.nested)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2012,6 +2012,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
(ty::Opaque, DefKind::OpaqueTy)
|
||||
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
|
||||
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
|
||||
| (ty::Weak, DefKind::TyAlias)
|
||||
);
|
||||
self.mk_ty_from_kind(Alias(kind, alias_ty))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,6 +300,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
ty::Placeholder(..) => "higher-ranked type".into(),
|
||||
ty::Bound(..) => "bound type variable".into(),
|
||||
ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
|
||||
ty::Alias(ty::Weak, _) => "type alias".into(),
|
||||
ty::Param(_) => "type parameter".into(),
|
||||
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ impl FlagComputation {
|
|||
|
||||
&ty::Alias(kind, data) => {
|
||||
self.add_flags(match kind {
|
||||
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||
ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION,
|
||||
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
|
||||
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -586,6 +586,24 @@ pub enum Clause<'tcx> {
|
|||
ConstArgHasType(Const<'tcx>, Ty<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> Binder<'tcx, Clause<'tcx>> {
|
||||
pub fn as_trait_clause(self) -> Option<Binder<'tcx, TraitPredicate<'tcx>>> {
|
||||
if let ty::Clause::Trait(trait_clause) = self.skip_binder() {
|
||||
Some(self.rebind(trait_clause))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_projection_clause(self) -> Option<Binder<'tcx, ProjectionPredicate<'tcx>>> {
|
||||
if let ty::Clause::Projection(projection_clause) = self.skip_binder() {
|
||||
Some(self.rebind(projection_clause))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub enum PredicateKind<'tcx> {
|
||||
|
|
@ -1203,6 +1221,17 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for TraitRef<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
|
||||
Binder::dummy(Clause::Trait(TraitPredicate {
|
||||
trait_ref: self,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
|
|
@ -1211,6 +1240,14 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for Binder<'tcx, TraitRef<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
|
||||
let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
|
||||
pred.to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
|
||||
|
|
@ -1240,6 +1277,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyTraitPredicate<'tcx> {
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
|
||||
self.map_bound(|p| Clause::Trait(p))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx)
|
||||
|
|
@ -1258,6 +1301,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx, Binder<'tcx, Clause<'tcx>>> for PolyProjectionPredicate<'tcx> {
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Binder<'tcx, Clause<'tcx>> {
|
||||
self.map_bound(|p| Clause::Projection(p))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx)
|
||||
|
|
@ -1327,6 +1376,23 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_clause(self) -> Option<Binder<'tcx, Clause<'tcx>>> {
|
||||
let predicate = self.kind();
|
||||
match predicate.skip_binder() {
|
||||
PredicateKind::Clause(clause) => Some(predicate.rebind(clause)),
|
||||
PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::WellFormed(..)
|
||||
| PredicateKind::ObjectSafe(..)
|
||||
| PredicateKind::ClosureKind(..)
|
||||
| PredicateKind::ConstEvaluatable(..)
|
||||
| PredicateKind::ConstEquate(..)
|
||||
| PredicateKind::Ambiguous
|
||||
| PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the bounds declared on a particular set of type
|
||||
|
|
|
|||
|
|
@ -731,7 +731,7 @@ pub trait PrettyPrinter<'tcx>:
|
|||
ty::Foreign(def_id) => {
|
||||
p!(print_def_path(def_id, &[]));
|
||||
}
|
||||
ty::Alias(ty::Projection | ty::Inherent, ref data) => {
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ref data) => {
|
||||
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
|
||||
&& self.tcx().is_impl_trait_in_trait(data.def_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -391,13 +391,13 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> {
|
|||
/// Relates `a` and `b` structurally, calling the relation for all nested values.
|
||||
/// Any semantic equality, e.g. of projections, and inference variables have to be
|
||||
/// handled by the caller.
|
||||
#[instrument(level = "trace", skip(relation), ret)]
|
||||
pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let tcx = relation.tcx();
|
||||
debug!("structurally_relate_tys: a={:?} b={:?}", a, b);
|
||||
match (a.kind(), b.kind()) {
|
||||
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
|
||||
// The caller should handle these cases!
|
||||
|
|
|
|||
|
|
@ -1231,6 +1231,7 @@ impl<'tcx> AliasTy<'tcx> {
|
|||
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
|
||||
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
|
||||
DefKind::OpaqueTy => ty::Opaque,
|
||||
DefKind::TyAlias => ty::Weak,
|
||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ pub struct CheckAlignment;
|
|||
|
||||
impl<'tcx> MirPass<'tcx> for CheckAlignment {
|
||||
fn is_enabled(&self, sess: &Session) -> bool {
|
||||
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
|
||||
if sess.target.llvm_target == "i686-pc-windows-msvc" {
|
||||
return false;
|
||||
}
|
||||
sess.opts.debug_assertions
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -479,11 +479,12 @@ impl<'tcx> Inliner<'tcx> {
|
|||
// Abort if type validation found anything fishy.
|
||||
checker.validation?;
|
||||
|
||||
// N.B. We still apply our cost threshold to #[inline(always)] functions.
|
||||
// That attribute is often applied to very large functions that exceed LLVM's (very
|
||||
// generous) inlining threshold. Such functions are very poor MIR inlining candidates.
|
||||
// Always inlining #[inline(always)] functions in MIR, on net, slows down the compiler.
|
||||
let cost = checker.cost;
|
||||
if let InlineAttr::Always = callee_attrs.inline {
|
||||
debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost);
|
||||
Ok(())
|
||||
} else if cost <= threshold {
|
||||
if cost <= threshold {
|
||||
debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold);
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -155,15 +155,17 @@ where
|
|||
// functions and statics defined in the local crate.
|
||||
let PlacedRootMonoItems { mut codegen_units, internalization_candidates, unique_inlined_stats } = {
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
|
||||
place_root_mono_items(cx, mono_items)
|
||||
let mut placed = place_root_mono_items(cx, mono_items);
|
||||
|
||||
for cgu in &mut placed.codegen_units {
|
||||
cgu.create_size_estimate(tcx);
|
||||
}
|
||||
|
||||
debug_dump(tcx, "ROOTS", &placed.codegen_units, placed.unique_inlined_stats);
|
||||
|
||||
placed
|
||||
};
|
||||
|
||||
for cgu in &mut codegen_units {
|
||||
cgu.create_size_estimate(tcx);
|
||||
}
|
||||
|
||||
debug_dump(tcx, "ROOTS", &codegen_units, unique_inlined_stats);
|
||||
|
||||
// Merge until we have at most `max_cgu_count` codegen units.
|
||||
// `merge_codegen_units` is responsible for updating the CGU size
|
||||
// estimates.
|
||||
|
|
@ -179,59 +181,34 @@ where
|
|||
// local functions the definition of which is marked with `#[inline]`.
|
||||
{
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
|
||||
place_inlined_mono_items(cx, &mut codegen_units)
|
||||
};
|
||||
place_inlined_mono_items(cx, &mut codegen_units);
|
||||
|
||||
for cgu in &mut codegen_units {
|
||||
cgu.create_size_estimate(tcx);
|
||||
for cgu in &mut codegen_units {
|
||||
cgu.create_size_estimate(tcx);
|
||||
}
|
||||
|
||||
debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats);
|
||||
}
|
||||
|
||||
debug_dump(tcx, "INLINE", &codegen_units, unique_inlined_stats);
|
||||
|
||||
// Next we try to make as many symbols "internal" as possible, so LLVM has
|
||||
// more freedom to optimize.
|
||||
if !tcx.sess.link_dead_code() {
|
||||
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
|
||||
internalize_symbols(cx, &mut codegen_units, internalization_candidates);
|
||||
|
||||
debug_dump(tcx, "INTERNALIZE", &codegen_units, unique_inlined_stats);
|
||||
}
|
||||
|
||||
// Mark one CGU for dead code, if necessary.
|
||||
let instrument_dead_code =
|
||||
tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions();
|
||||
|
||||
if instrument_dead_code {
|
||||
assert!(
|
||||
codegen_units.len() > 0,
|
||||
"There must be at least one CGU that code coverage data can be generated in."
|
||||
);
|
||||
|
||||
// Find the smallest CGU that has exported symbols and put the dead
|
||||
// function stubs in that CGU. We look for exported symbols to increase
|
||||
// the likelihood the linker won't throw away the dead functions.
|
||||
// FIXME(#92165): In order to truly resolve this, we need to make sure
|
||||
// the object file (CGU) containing the dead function stubs is included
|
||||
// in the final binary. This will probably require forcing these
|
||||
// function symbols to be included via `-u` or `/include` linker args.
|
||||
let mut cgus: Vec<_> = codegen_units.iter_mut().collect();
|
||||
cgus.sort_by_key(|cgu| cgu.size_estimate());
|
||||
|
||||
let dead_code_cgu =
|
||||
if let Some(cgu) = cgus.into_iter().rev().find(|cgu| {
|
||||
cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)
|
||||
}) {
|
||||
cgu
|
||||
} else {
|
||||
// If there are no CGUs that have externally linked items,
|
||||
// then we just pick the first CGU as a fallback.
|
||||
&mut codegen_units[0]
|
||||
};
|
||||
dead_code_cgu.make_code_coverage_dead_code_cgu();
|
||||
mark_code_coverage_dead_code_cgu(&mut codegen_units);
|
||||
}
|
||||
|
||||
// Ensure CGUs are sorted by name, so that we get deterministic results.
|
||||
assert!(codegen_units.is_sorted_by(|a, b| Some(a.name().as_str().cmp(b.name().as_str()))));
|
||||
|
||||
debug_dump(tcx, "FINAL", &codegen_units, unique_inlined_stats);
|
||||
|
||||
codegen_units
|
||||
}
|
||||
|
||||
|
|
@ -363,9 +340,7 @@ fn merge_codegen_units<'tcx>(
|
|||
|
||||
// Move the mono-items from `smallest` to `second_smallest`
|
||||
second_smallest.modify_size_estimate(smallest.size_estimate());
|
||||
for (k, v) in smallest.items_mut().drain() {
|
||||
second_smallest.items_mut().insert(k, v);
|
||||
}
|
||||
second_smallest.items_mut().extend(smallest.items_mut().drain());
|
||||
|
||||
// Record that `second_smallest` now contains all the stuff that was
|
||||
// in `smallest` before.
|
||||
|
|
@ -545,6 +520,28 @@ fn internalize_symbols<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn mark_code_coverage_dead_code_cgu<'tcx>(codegen_units: &mut [CodegenUnit<'tcx>]) {
|
||||
assert!(!codegen_units.is_empty());
|
||||
|
||||
// Find the smallest CGU that has exported symbols and put the dead
|
||||
// function stubs in that CGU. We look for exported symbols to increase
|
||||
// the likelihood the linker won't throw away the dead functions.
|
||||
// FIXME(#92165): In order to truly resolve this, we need to make sure
|
||||
// the object file (CGU) containing the dead function stubs is included
|
||||
// in the final binary. This will probably require forcing these
|
||||
// function symbols to be included via `-u` or `/include` linker args.
|
||||
let dead_code_cgu = codegen_units
|
||||
.iter_mut()
|
||||
.filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External))
|
||||
.min_by_key(|cgu| cgu.size_estimate());
|
||||
|
||||
// If there are no CGUs that have externally linked items, then we just
|
||||
// pick the first CGU as a fallback.
|
||||
let dead_code_cgu = if let Some(cgu) = dead_code_cgu { cgu } else { &mut codegen_units[0] };
|
||||
|
||||
dead_code_cgu.make_code_coverage_dead_code_cgu();
|
||||
}
|
||||
|
||||
fn characteristic_def_id_of_mono_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mono_item: MonoItem<'tcx>,
|
||||
|
|
|
|||
|
|
@ -2029,17 +2029,14 @@ impl<'a> Parser<'a> {
|
|||
let recovered = self.recover_after_dot();
|
||||
let token = recovered.as_ref().unwrap_or(&self.token);
|
||||
match token::Lit::from_token(token) {
|
||||
Some(token_lit) => {
|
||||
match MetaItemLit::from_token_lit(token_lit, token.span) {
|
||||
Some(lit) => {
|
||||
match MetaItemLit::from_token_lit(lit, token.span) {
|
||||
Ok(lit) => {
|
||||
self.bump();
|
||||
Some(lit)
|
||||
}
|
||||
Err(err) => {
|
||||
let span = token.span;
|
||||
let token::Literal(lit) = token.kind else {
|
||||
unreachable!();
|
||||
};
|
||||
let span = token.uninterpolated_span();
|
||||
self.bump();
|
||||
report_lit_error(&self.sess, err, lit, span);
|
||||
// Pack possible quotes and prefixes from the original literal into
|
||||
|
|
|
|||
|
|
@ -242,6 +242,9 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Weak, alias) => {
|
||||
self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty);
|
||||
}
|
||||
ty::Alias(ty::Projection, proj) => {
|
||||
if self.def_id_visitor.skip_assoc_tys() {
|
||||
// Visitors searching for minimal visibility/reachability want to
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ impl HygieneData {
|
|||
self.normalize_to_macro_rules(call_site_ctxt)
|
||||
};
|
||||
|
||||
if call_site_ctxt == SyntaxContext::root() {
|
||||
if call_site_ctxt.is_root() {
|
||||
return self.apply_mark_internal(ctxt, expn_id, transparency);
|
||||
}
|
||||
|
||||
|
|
@ -671,12 +671,17 @@ impl SyntaxContext {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn as_u32(self) -> u32 {
|
||||
pub const fn is_root(self) -> bool {
|
||||
self.0 == SyntaxContext::root().as_u32()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_u32(raw: u32) -> SyntaxContext {
|
||||
pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
|
||||
SyntaxContext(raw)
|
||||
}
|
||||
|
||||
|
|
@ -1500,7 +1505,7 @@ impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
|
|||
const TAG_EXPANSION: u8 = 0;
|
||||
const TAG_NO_EXPANSION: u8 = 1;
|
||||
|
||||
if *self == SyntaxContext::root() {
|
||||
if self.is_root() {
|
||||
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
|
||||
} else {
|
||||
TAG_EXPANSION.hash_stable(ctx, hasher);
|
||||
|
|
|
|||
|
|
@ -826,9 +826,9 @@ impl Span {
|
|||
// Return the macro span on its own to avoid weird diagnostic output. It is preferable to
|
||||
// have an incomplete span than a completely nonsensical one.
|
||||
if span_data.ctxt != end_data.ctxt {
|
||||
if span_data.ctxt == SyntaxContext::root() {
|
||||
if span_data.ctxt.is_root() {
|
||||
return end;
|
||||
} else if end_data.ctxt == SyntaxContext::root() {
|
||||
} else if end_data.ctxt.is_root() {
|
||||
return self;
|
||||
}
|
||||
// Both spans fall within a macro.
|
||||
|
|
@ -837,7 +837,7 @@ impl Span {
|
|||
Span::new(
|
||||
cmp::min(span_data.lo, end_data.lo),
|
||||
cmp::max(span_data.hi, end_data.hi),
|
||||
if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
|
||||
if span_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt },
|
||||
if span_data.parent == end_data.parent { span_data.parent } else { None },
|
||||
)
|
||||
}
|
||||
|
|
@ -855,7 +855,7 @@ impl Span {
|
|||
Span::new(
|
||||
span.hi,
|
||||
end.lo,
|
||||
if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
|
||||
if end.ctxt.is_root() { end.ctxt } else { span.ctxt },
|
||||
if span.parent == end.parent { span.parent } else { None },
|
||||
)
|
||||
}
|
||||
|
|
@ -879,9 +879,9 @@ impl Span {
|
|||
// Return the macro span on its own to avoid weird diagnostic output. It is preferable to
|
||||
// have an incomplete span than a completely nonsensical one.
|
||||
if span_data.ctxt != end_data.ctxt {
|
||||
if span_data.ctxt == SyntaxContext::root() {
|
||||
if span_data.ctxt.is_root() {
|
||||
return end;
|
||||
} else if end_data.ctxt == SyntaxContext::root() {
|
||||
} else if end_data.ctxt.is_root() {
|
||||
return self;
|
||||
}
|
||||
// Both spans fall within a macro.
|
||||
|
|
@ -890,7 +890,7 @@ impl Span {
|
|||
Span::new(
|
||||
span_data.lo,
|
||||
end_data.lo,
|
||||
if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
|
||||
if end_data.ctxt.is_root() { end_data.ctxt } else { span_data.ctxt },
|
||||
if span_data.parent == end_data.parent { span_data.parent } else { None },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1156,6 +1156,7 @@ symbols! {
|
|||
ptr_null_mut,
|
||||
ptr_offset_from,
|
||||
ptr_offset_from_unsigned,
|
||||
ptr_unique,
|
||||
pub_macro_rules,
|
||||
pub_restricted,
|
||||
public,
|
||||
|
|
|
|||
|
|
@ -483,6 +483,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
|
|||
}
|
||||
|
||||
ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"),
|
||||
ty::Alias(ty::Weak, _) => bug!("symbol_names: unexpected weak projection"),
|
||||
ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"),
|
||||
ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||
fn consider_implied_clause(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
|
||||
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
||||
|
|
@ -131,7 +131,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||
fn consider_alias_bound_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
||||
ecx.validate_alias_bound_self_from_param_env(goal)
|
||||
|
|
@ -144,7 +144,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||
fn consider_object_bound_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
||||
let tcx = ecx.tcx();
|
||||
|
|
@ -467,11 +467,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
candidates: &mut Vec<Candidate<'tcx>>,
|
||||
) {
|
||||
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
|
||||
match G::consider_implied_clause(self, goal, assumption, []) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
|
||||
if let Some(clause) = assumption.as_clause() {
|
||||
match G::consider_implied_clause(self, goal, clause, []) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -508,20 +510,23 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
| ty::Placeholder(..)
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Alias(ty::Inherent, _)
|
||||
| ty::Alias(ty::Weak, _)
|
||||
| ty::Error(_) => return,
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
|
||||
// Excluding IATs here as they don't have meaningful item bounds.
|
||||
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
|
||||
ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
|
||||
};
|
||||
|
||||
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
|
||||
{
|
||||
match G::consider_alias_bound_candidate(self, goal, assumption) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
|
||||
if let Some(clause) = assumption.as_clause() {
|
||||
match G::consider_alias_bound_candidate(self, goal, clause) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -675,18 +680,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
// projection predicates that we reach by elaborating the principal trait ref,
|
||||
// since that'll cause ambiguity.
|
||||
//
|
||||
// We can remove this when we have implemented intersections in responses.
|
||||
// We can remove this when we have implemented lifetime intersections in responses.
|
||||
if assumption.to_opt_poly_projection_pred().is_some()
|
||||
&& !own_bounds.contains(&assumption)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
match G::consider_object_bound_candidate(self, goal, assumption) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
||||
if let Some(clause) = assumption.as_clause() {
|
||||
match G::consider_object_bound_candidate(self, goal, clause) {
|
||||
Ok(result) => {
|
||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
|||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(_) => {
|
||||
|
|
|
|||
|
|
@ -208,8 +208,25 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
|
|||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
let r = self.infcx.shallow_resolve(r);
|
||||
fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match self.canonicalize_mode {
|
||||
CanonicalizeMode::Input => {
|
||||
// Don't resolve infer vars in input, since it affects
|
||||
// caching and may cause trait selection bugs which rely
|
||||
// on regions to be equal.
|
||||
}
|
||||
CanonicalizeMode::Response { .. } => {
|
||||
if let ty::ReVar(vid) = *r {
|
||||
r = self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.infcx.tcx, vid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let kind = match *r {
|
||||
ty::ReLateBound(..) => return r,
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||
let new_canonical_response =
|
||||
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
|
||||
if !new_canonical_response.value.var_values.is_identity() {
|
||||
// We only check for modulo regions as we convert all regions in
|
||||
// the input to new existentials, even if they're expected to be
|
||||
// `'static` or a placeholder region.
|
||||
if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
|
||||
bug!(
|
||||
"unstable result: re-canonicalized goal={canonical_goal:#?} \
|
||||
first_response={canonical_response:#?} \
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ mod opaques;
|
|||
mod project_goals;
|
||||
mod search_graph;
|
||||
mod trait_goals;
|
||||
mod weak_types;
|
||||
|
||||
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
|
||||
pub use fulfill::FulfillmentCtxt;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
}
|
||||
DefKind::AnonConst => self.normalize_anon_const(goal),
|
||||
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
|
||||
DefKind::TyAlias => self.normalize_weak_type(goal),
|
||||
kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
|
||||
}
|
||||
}
|
||||
|
|
@ -105,15 +106,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
|
||||
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
|
||||
if let Some(projection_pred) = assumption.as_projection_clause()
|
||||
&& projection_pred.projection_def_id() == goal.predicate.def_id()
|
||||
{
|
||||
ecx.probe(|ecx| {
|
||||
let assumption_projection_pred =
|
||||
ecx.instantiate_binder_with_infer(poly_projection_pred);
|
||||
ecx.instantiate_binder_with_infer(projection_pred);
|
||||
ecx.eq(
|
||||
goal.param_env,
|
||||
goal.predicate.projection_ty,
|
||||
|
|
|
|||
|
|
@ -81,17 +81,17 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Predicate<'tcx>,
|
||||
assumption: ty::Binder<'tcx, ty::Clause<'tcx>>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
|
||||
&& poly_trait_pred.def_id() == goal.predicate.def_id()
|
||||
&& poly_trait_pred.polarity() == goal.predicate.polarity
|
||||
if let Some(trait_clause) = assumption.as_trait_clause()
|
||||
&& trait_clause.def_id() == goal.predicate.def_id()
|
||||
&& trait_clause.polarity() == goal.predicate.polarity
|
||||
{
|
||||
// FIXME: Constness
|
||||
ecx.probe(|ecx| {
|
||||
let assumption_trait_pred =
|
||||
ecx.instantiate_binder_with_infer(poly_trait_pred);
|
||||
ecx.instantiate_binder_with_infer(trait_clause);
|
||||
ecx.eq(
|
||||
goal.param_env,
|
||||
goal.predicate.trait_ref,
|
||||
|
|
@ -618,7 +618,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
|
||||
| ty::Placeholder(..) => Some(Err(NoSolution)),
|
||||
|
||||
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
|
||||
|
|
|
|||
19
compiler/rustc_trait_selection/src/solve/weak_types.rs
Normal file
19
compiler/rustc_trait_selection/src/solve/weak_types.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
|
||||
use super::EvalCtxt;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
pub(super) fn normalize_weak_type(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let weak_ty = goal.predicate.projection_ty;
|
||||
let expected = goal.predicate.term.ty().expect("no such thing as a const alias");
|
||||
|
||||
let actual = tcx.type_of(weak_ty.def_id).subst(tcx, weak_ty.substs);
|
||||
self.eq(goal.param_env, expected, actual)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
|
@ -292,7 +292,12 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
|
|||
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
|
||||
})
|
||||
.chain(obligations)
|
||||
.find(|o| !selcx.predicate_may_hold_fatal(o));
|
||||
.find(|o| {
|
||||
selcx.evaluate_root_obligation(o).map_or(
|
||||
false, // Overflow has occurred, and treat the obligation as possibly holding.
|
||||
|result| !result.may_apply(),
|
||||
)
|
||||
});
|
||||
|
||||
if let Some(failing_obligation) = opt_failing_obligation {
|
||||
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
||||
|
|
@ -690,7 +695,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
|
|||
| ty::RawPtr(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => {
|
||||
self.found_non_local_ty(ty)
|
||||
}
|
||||
|
||||
ty::Param(..) => self.found_param_ty(ty),
|
||||
|
||||
|
|
|
|||
|
|
@ -1824,12 +1824,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
ty::Alias(ty::Projection, ..) => Some(12),
|
||||
ty::Alias(ty::Inherent, ..) => Some(13),
|
||||
ty::Alias(ty::Opaque, ..) => Some(14),
|
||||
ty::Never => Some(15),
|
||||
ty::Adt(..) => Some(16),
|
||||
ty::Generator(..) => Some(17),
|
||||
ty::Foreign(..) => Some(18),
|
||||
ty::GeneratorWitness(..) => Some(19),
|
||||
ty::GeneratorWitnessMIR(..) => Some(20),
|
||||
ty::Alias(ty::Weak, ..) => Some(15),
|
||||
ty::Never => Some(16),
|
||||
ty::Adt(..) => Some(17),
|
||||
ty::Generator(..) => Some(18),
|
||||
ty::Foreign(..) => Some(19),
|
||||
ty::GeneratorWitness(..) => Some(20),
|
||||
ty::GeneratorWitnessMIR(..) => Some(21),
|
||||
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3198,6 +3198,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
)
|
||||
});
|
||||
}
|
||||
ObligationCauseCode::TypeAlias(ref nested, span, def_id) => {
|
||||
// #74711: avoid a stack overflow
|
||||
ensure_sufficient_stack(|| {
|
||||
self.note_obligation_cause_code(
|
||||
body_id,
|
||||
err,
|
||||
predicate,
|
||||
param_env,
|
||||
nested,
|
||||
obligated_types,
|
||||
seen_requirements,
|
||||
)
|
||||
});
|
||||
let mut multispan = MultiSpan::from(span);
|
||||
multispan.push_span_label(span, "required by this bound");
|
||||
err.span_note(
|
||||
multispan,
|
||||
format!(
|
||||
"required by a bound on the type alias `{}`",
|
||||
self.infcx.tcx.item_name(def_id)
|
||||
),
|
||||
);
|
||||
}
|
||||
ObligationCauseCode::FunctionArgumentObligation {
|
||||
arg_hir_id,
|
||||
call_hir_id,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId;
|
|||
|
||||
pub use rustc_middle::traits::query::OutlivesBound;
|
||||
|
||||
type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
|
||||
pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
|
||||
pub trait InferCtxtExt<'a, 'tcx> {
|
||||
fn implied_outlives_bounds(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
use super::specialization_graph;
|
||||
use super::translate_substs;
|
||||
use super::util;
|
||||
use super::ImplSourceUserDefinedData;
|
||||
use super::MismatchedProjectionTypes;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
|
|
@ -10,10 +11,6 @@ use super::PredicateObligation;
|
|||
use super::Selection;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
use super::{
|
||||
ImplSourceClosureData, ImplSourceFnPointerData, ImplSourceFutureData, ImplSourceGeneratorData,
|
||||
ImplSourceUserDefinedData,
|
||||
};
|
||||
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||
|
||||
use crate::errors::InherentProjectionNormalizationOverflow;
|
||||
|
|
@ -30,7 +27,7 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_infer::infer::at::At;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::ImplSourceBuiltinData;
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
|
||||
|
|
@ -621,6 +618,30 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
|||
);
|
||||
normalized_ty
|
||||
}
|
||||
ty::Weak => {
|
||||
let infcx = self.selcx.infcx;
|
||||
self.obligations.extend(
|
||||
infcx
|
||||
.tcx
|
||||
.predicates_of(data.def_id)
|
||||
.instantiate_own(infcx.tcx, data.substs)
|
||||
.map(|(mut predicate, span)| {
|
||||
if data.has_escaping_bound_vars() {
|
||||
(predicate, ..) = BoundVarReplacer::replace_bound_vars(
|
||||
infcx,
|
||||
&mut self.universes,
|
||||
predicate,
|
||||
);
|
||||
}
|
||||
let mut cause = self.cause.clone();
|
||||
cause.map_code(|code| {
|
||||
ObligationCauseCode::TypeAlias(code, span, data.def_id)
|
||||
});
|
||||
Obligation::new(infcx.tcx, cause, self.param_env, predicate)
|
||||
}),
|
||||
);
|
||||
infcx.tcx.type_of(data.def_id).subst(infcx.tcx, data.substs).fold_with(self)
|
||||
}
|
||||
|
||||
ty::Inherent if !data.has_escaping_bound_vars() => {
|
||||
// This branch is *mostly* just an optimization: when we don't
|
||||
|
|
@ -1545,7 +1566,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
|||
// Check whether the self-type is itself a projection.
|
||||
// If so, extract what we know from the trait and try to come up with a good answer.
|
||||
let bounds = match *obligation.predicate.self_ty().kind() {
|
||||
// Excluding IATs here as they don't have meaningful item bounds.
|
||||
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
|
||||
ty::Alias(ty::Projection | ty::Opaque, ref data) => {
|
||||
tcx.item_bounds(data.def_id).subst(tcx, data.substs)
|
||||
}
|
||||
|
|
@ -1696,11 +1717,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
};
|
||||
|
||||
let eligible = match &impl_source {
|
||||
super::ImplSource::Closure(_)
|
||||
| super::ImplSource::Generator(_)
|
||||
| super::ImplSource::Future(_)
|
||||
| super::ImplSource::FnPointer(_)
|
||||
| super::ImplSource::TraitAlias(_) => true,
|
||||
super::ImplSource::TraitAlias(_) => true,
|
||||
super::ImplSource::UserDefined(impl_data) => {
|
||||
// We have to be careful when projecting out of an
|
||||
// impl because of specialization. If we are not in
|
||||
|
|
@ -1758,7 +1775,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
|
||||
let lang_items = selcx.tcx().lang_items();
|
||||
if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) {
|
||||
if [lang_items.gen_trait(), lang_items.future_trait()].contains(&Some(poly_trait_ref.def_id()))
|
||||
|| selcx.tcx().fn_trait_kind_from_def_id(poly_trait_ref.def_id()).is_some()
|
||||
{
|
||||
true
|
||||
} else if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) {
|
||||
match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
|
|
@ -1905,9 +1926,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||
// why we special case object types.
|
||||
false
|
||||
}
|
||||
super::ImplSource::AutoImpl(..)
|
||||
| super::ImplSource::TraitUpcasting(_)
|
||||
| super::ImplSource::ConstDestruct(_) => {
|
||||
| super::ImplSource::TraitUpcasting(_) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.delay_span_bug(
|
||||
obligation.cause.span,
|
||||
|
|
@ -1971,17 +1990,27 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||
) -> Progress<'tcx> {
|
||||
match impl_source {
|
||||
super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Future(data) => confirm_future_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data),
|
||||
super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Builtin(data) => confirm_builtin_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Builtin(data) => {
|
||||
let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx());
|
||||
let lang_items = selcx.tcx().lang_items();
|
||||
if lang_items.gen_trait() == Some(trait_def_id) {
|
||||
confirm_generator_candidate(selcx, obligation, data)
|
||||
} else if lang_items.future_trait() == Some(trait_def_id) {
|
||||
confirm_future_candidate(selcx, obligation, data)
|
||||
} else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() {
|
||||
if obligation.predicate.self_ty().is_closure() {
|
||||
confirm_closure_candidate(selcx, obligation, data)
|
||||
} else {
|
||||
confirm_fn_pointer_candidate(selcx, obligation, data)
|
||||
}
|
||||
} else {
|
||||
confirm_builtin_candidate(selcx, obligation, data)
|
||||
}
|
||||
}
|
||||
super::ImplSource::Object(_)
|
||||
| super::ImplSource::AutoImpl(..)
|
||||
| super::ImplSource::Param(..)
|
||||
| super::ImplSource::TraitUpcasting(_)
|
||||
| super::ImplSource::TraitAlias(..)
|
||||
| super::ImplSource::ConstDestruct(_) => {
|
||||
| super::ImplSource::TraitAlias(..) => {
|
||||
// we don't create Select candidates with this kind of resolution
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
|
|
@ -1995,9 +2024,14 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||
fn confirm_generator_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
impl_source: ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>,
|
||||
nested: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Progress<'tcx> {
|
||||
let gen_sig = impl_source.substs.as_generator().poly_sig();
|
||||
let ty::Generator(_, substs, _) =
|
||||
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
let gen_sig = substs.as_generator().poly_sig();
|
||||
let Normalized { value: gen_sig, obligations } = normalize_with_depth(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
|
|
@ -2035,16 +2069,21 @@ fn confirm_generator_candidate<'cx, 'tcx>(
|
|||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, false)
|
||||
.with_addl_obligations(impl_source.nested)
|
||||
.with_addl_obligations(nested)
|
||||
.with_addl_obligations(obligations)
|
||||
}
|
||||
|
||||
fn confirm_future_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
impl_source: ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>,
|
||||
nested: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Progress<'tcx> {
|
||||
let gen_sig = impl_source.substs.as_generator().poly_sig();
|
||||
let ty::Generator(_, substs, _) =
|
||||
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
let gen_sig = substs.as_generator().poly_sig();
|
||||
let Normalized { value: gen_sig, obligations } = normalize_with_depth(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
|
|
@ -2074,14 +2113,14 @@ fn confirm_future_candidate<'cx, 'tcx>(
|
|||
});
|
||||
|
||||
confirm_param_env_candidate(selcx, obligation, predicate, false)
|
||||
.with_addl_obligations(impl_source.nested)
|
||||
.with_addl_obligations(nested)
|
||||
.with_addl_obligations(obligations)
|
||||
}
|
||||
|
||||
fn confirm_builtin_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
data: ImplSourceBuiltinData<PredicateObligation<'tcx>>,
|
||||
data: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
let self_ty = obligation.predicate.self_ty();
|
||||
|
|
@ -2129,15 +2168,15 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
|
|||
|
||||
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
|
||||
.with_addl_obligations(obligations)
|
||||
.with_addl_obligations(data.nested)
|
||||
.with_addl_obligations(data)
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>,
|
||||
nested: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Progress<'tcx> {
|
||||
let fn_type = selcx.infcx.shallow_resolve(fn_pointer_impl_source.fn_ty);
|
||||
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
let sig = fn_type.fn_sig(selcx.tcx());
|
||||
let Normalized { value: sig, obligations } = normalize_with_depth(
|
||||
selcx,
|
||||
|
|
@ -2148,16 +2187,21 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
|||
);
|
||||
|
||||
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
|
||||
.with_addl_obligations(fn_pointer_impl_source.nested)
|
||||
.with_addl_obligations(nested)
|
||||
.with_addl_obligations(obligations)
|
||||
}
|
||||
|
||||
fn confirm_closure_candidate<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
impl_source: ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>,
|
||||
nested: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Progress<'tcx> {
|
||||
let closure_sig = impl_source.substs.as_closure().sig();
|
||||
let ty::Closure(_, substs) =
|
||||
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
let closure_sig = substs.as_closure().sig();
|
||||
let Normalized { value: closure_sig, obligations } = normalize_with_depth(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
|
|
@ -2169,7 +2213,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
|
|||
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
|
||||
|
||||
confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
|
||||
.with_addl_obligations(impl_source.nested)
|
||||
.with_addl_obligations(nested)
|
||||
.with_addl_obligations(obligations)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
|||
|
||||
ty::Opaque => ty.try_super_fold_with(self)?,
|
||||
|
||||
ty::Projection | ty::Inherent => {
|
||||
ty::Projection | ty::Inherent | ty::Weak => {
|
||||
// See note in `rustc_trait_selection::traits::project`
|
||||
|
||||
let infcx = self.infcx;
|
||||
|
|
@ -282,6 +282,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
|||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
let result = match kind {
|
||||
ty::Projection => tcx.normalize_projection_ty(c_data),
|
||||
ty::Weak => tcx.normalize_weak_ty(c_data),
|
||||
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
|
||||
_ => unreachable!(),
|
||||
}?;
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// Before we go into the whole placeholder thing, just
|
||||
// quickly check if the self-type is a projection at all.
|
||||
match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
|
||||
// Excluding IATs here as they don't have meaningful item bounds.
|
||||
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
|
||||
ty::Alias(ty::Projection | ty::Opaque, _) => {}
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
span_bug!(
|
||||
|
|
|
|||
|
|
@ -27,11 +27,9 @@ use crate::traits::vtable::{
|
|||
};
|
||||
use crate::traits::{
|
||||
BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
|
||||
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
||||
ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData,
|
||||
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData,
|
||||
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation,
|
||||
ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
|
||||
ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceTraitUpcastingData,
|
||||
ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
|
||||
OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
|
||||
TraitNotObjectSafe, TraitObligation, Unimplemented,
|
||||
};
|
||||
|
||||
|
|
@ -72,7 +70,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
AutoImplCandidate => {
|
||||
let data = self.confirm_auto_impl_candidate(obligation);
|
||||
ImplSource::AutoImpl(data)
|
||||
ImplSource::Builtin(data)
|
||||
}
|
||||
|
||||
ProjectionCandidate(idx, constness) => {
|
||||
|
|
@ -87,22 +85,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
ClosureCandidate { .. } => {
|
||||
let vtable_closure = self.confirm_closure_candidate(obligation)?;
|
||||
ImplSource::Closure(vtable_closure)
|
||||
ImplSource::Builtin(vtable_closure)
|
||||
}
|
||||
|
||||
GeneratorCandidate => {
|
||||
let vtable_generator = self.confirm_generator_candidate(obligation)?;
|
||||
ImplSource::Generator(vtable_generator)
|
||||
ImplSource::Builtin(vtable_generator)
|
||||
}
|
||||
|
||||
FutureCandidate => {
|
||||
let vtable_future = self.confirm_future_candidate(obligation)?;
|
||||
ImplSource::Future(vtable_future)
|
||||
ImplSource::Builtin(vtable_future)
|
||||
}
|
||||
|
||||
FnPointerCandidate { is_const } => {
|
||||
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
|
||||
ImplSource::FnPointer(data)
|
||||
ImplSource::Builtin(data)
|
||||
}
|
||||
|
||||
TraitAliasCandidate => {
|
||||
|
|
@ -114,7 +112,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// This indicates something like `Trait + Send: Send`. In this case, we know that
|
||||
// this holds because that's what the object type is telling us, and there's really
|
||||
// no additional obligations to prove and no types in particular to unify, etc.
|
||||
ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)
|
||||
ImplSource::Builtin(Vec::new())
|
||||
}
|
||||
|
||||
BuiltinUnsizeCandidate => {
|
||||
|
|
@ -129,7 +127,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
ConstDestructCandidate(def_id) => {
|
||||
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
|
||||
ImplSource::ConstDestruct(data)
|
||||
ImplSource::Builtin(data)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -163,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
|
||||
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
|
||||
let (def_id, substs) = match *placeholder_self_ty.kind() {
|
||||
// Excluding IATs here as they don't have meaningful item bounds.
|
||||
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
|
||||
ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
(def_id, substs)
|
||||
}
|
||||
|
|
@ -244,7 +242,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
has_nested: bool,
|
||||
) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> {
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
|
||||
|
||||
let lang_items = self.tcx().lang_items();
|
||||
|
|
@ -277,14 +275,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
debug!(?obligations);
|
||||
|
||||
ImplSourceBuiltinData { nested: obligations }
|
||||
obligations
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn confirm_transmutability_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
use rustc_transmute::{Answer, Condition};
|
||||
#[instrument(level = "debug", skip(tcx, obligation, predicate))]
|
||||
fn flatten_answer_tree<'tcx>(
|
||||
|
|
@ -369,7 +367,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
debug!(?fully_flattened);
|
||||
Ok(ImplSourceBuiltinData { nested: fully_flattened })
|
||||
Ok(fully_flattened)
|
||||
}
|
||||
|
||||
/// This handles the case where an `auto trait Foo` impl is being used.
|
||||
|
|
@ -380,7 +378,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
fn confirm_auto_impl_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
debug!(?obligation, "confirm_auto_impl_candidate");
|
||||
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
|
|
@ -394,7 +392,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &TraitObligation<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
|
||||
) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
debug!(?nested, "vtable_auto_impl");
|
||||
ensure_sufficient_stack(|| {
|
||||
let cause = obligation.derived_cause(BuiltinDerivedObligation);
|
||||
|
|
@ -424,7 +422,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
debug!(?obligations, "vtable_auto_impl");
|
||||
|
||||
ImplSourceAutoImplData { trait_def_id, nested: obligations }
|
||||
obligations
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +485,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
index: usize,
|
||||
) -> Result<ImplSourceObjectData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<ImplSourceObjectData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
debug!(?obligation, ?index, "confirm_object_candidate");
|
||||
|
||||
|
|
@ -654,15 +652,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
(unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
|
||||
);
|
||||
|
||||
Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
|
||||
Ok(ImplSourceObjectData {
|
||||
upcast_trait_def_id: upcast_trait_ref.def_id(),
|
||||
vtable_base,
|
||||
nested,
|
||||
})
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
is_const: bool,
|
||||
) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
||||
{
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
debug!(?obligation, "confirm_fn_pointer_candidate");
|
||||
|
||||
let tcx = self.tcx();
|
||||
|
|
@ -714,7 +715,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let tr = ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [output_ty]);
|
||||
nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr));
|
||||
|
||||
Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested })
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
fn confirm_trait_alias_candidate(
|
||||
|
|
@ -746,8 +747,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
fn confirm_generator_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Result<ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
||||
{
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
// Okay to skip binder because the substs on generator types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters.
|
||||
|
|
@ -780,13 +780,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
||||
debug!(?trait_ref, ?nested, "generator candidate obligations");
|
||||
|
||||
Ok(ImplSourceGeneratorData { generator_def_id, substs, nested })
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
fn confirm_future_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Result<ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
// Okay to skip binder because the substs on generator types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters.
|
||||
|
|
@ -810,14 +810,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
||||
debug!(?trait_ref, ?nested, "future candidate obligations");
|
||||
|
||||
Ok(ImplSourceFutureData { generator_def_id, substs, nested })
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn confirm_closure_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let kind = self
|
||||
.tcx()
|
||||
.fn_trait_kind_from_def_id(obligation.predicate.def_id())
|
||||
|
|
@ -844,7 +844,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
));
|
||||
}
|
||||
|
||||
Ok(ImplSourceClosureData { closure_def_id, substs, nested })
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
/// In the case of closure types and fn pointers,
|
||||
|
|
@ -912,8 +912,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
idx: usize,
|
||||
) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
||||
{
|
||||
) -> Result<ImplSourceTraitUpcastingData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
|
||||
|
|
@ -1010,13 +1009,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let vtable_vptr_slot =
|
||||
prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap();
|
||||
|
||||
Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
|
||||
Ok(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested })
|
||||
}
|
||||
|
||||
fn confirm_builtin_unsize_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
|
||||
|
|
@ -1217,17 +1216,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
_ => bug!("source: {source}, target: {target}"),
|
||||
};
|
||||
|
||||
Ok(ImplSourceBuiltinData { nested })
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
fn confirm_const_destruct_candidate(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
impl_def_id: Option<DefId>,
|
||||
) -> Result<ImplSourceConstDestructData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
// `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop`
|
||||
if !obligation.is_const() {
|
||||
return Ok(ImplSourceConstDestructData { nested: vec![] });
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
|
||||
|
|
@ -1381,6 +1380,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(ImplSourceConstDestructData { nested })
|
||||
Ok(nested)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -518,19 +518,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// The result is "true" if the obligation *may* hold and "false" if
|
||||
// we can be sure it does not.
|
||||
|
||||
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
|
||||
pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
|
||||
debug!(?obligation, "predicate_may_hold_fatal");
|
||||
|
||||
// This fatal query is a stopgap that should only be used in standard mode,
|
||||
// where we do not expect overflow to be propagated.
|
||||
assert!(self.query_mode == TraitQueryMode::Standard);
|
||||
|
||||
self.evaluate_root_obligation(obligation)
|
||||
.expect("Overflow should be caught earlier in standard query mode")
|
||||
.may_apply()
|
||||
}
|
||||
|
||||
/// Evaluates whether the obligation `obligation` can be satisfied
|
||||
/// and returns an `EvaluationResult`. This is meant for the
|
||||
/// *initial* call.
|
||||
|
|
@ -2327,7 +2314,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
| ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent, ..)
|
||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
|
||||
|
|
|
|||
|
|
@ -243,12 +243,12 @@ pub fn upcast_choices<'tcx>(
|
|||
/// `object.upcast_trait_ref`) within the vtable for `object`.
|
||||
pub fn get_vtable_index_of_object_method<'tcx, N>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
object: &super::ImplSourceObjectData<'tcx, N>,
|
||||
object: &super::ImplSourceObjectData<N>,
|
||||
method_def_id: DefId,
|
||||
) -> Option<usize> {
|
||||
// Count number of methods preceding the one we are selecting and
|
||||
// add them to the total offset.
|
||||
tcx.own_existential_vtable_entries(object.upcast_trait_ref.def_id())
|
||||
tcx.own_existential_vtable_entries(object.upcast_trait_def_id)
|
||||
.iter()
|
||||
.copied()
|
||||
.position(|def_id| def_id == method_def_id)
|
||||
|
|
|
|||
|
|
@ -731,6 +731,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, ty::AliasTy { def_id, substs, .. }) => {
|
||||
let obligations = self.nominal_obligations(def_id, substs);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
|
||||
ty::Dynamic(data, r, _) => {
|
||||
// WfObject
|
||||
//
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
|
|||
substitution: substs.lower_into(interner),
|
||||
}))
|
||||
}
|
||||
ty::Alias(ty::Weak, ty::AliasTy { .. }) => unimplemented!(),
|
||||
ty::Alias(ty::Inherent, _) => unimplemented!(),
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
|
|||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub(crate) fn provide(p: &mut Providers) {
|
||||
*p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p };
|
||||
*p = Providers {
|
||||
normalize_projection_ty,
|
||||
normalize_weak_ty,
|
||||
normalize_inherent_projection_ty,
|
||||
..*p
|
||||
};
|
||||
}
|
||||
|
||||
fn normalize_projection_ty<'tcx>(
|
||||
|
|
@ -43,6 +48,33 @@ fn normalize_projection_ty<'tcx>(
|
|||
)
|
||||
}
|
||||
|
||||
fn normalize_weak_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalProjectionGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
|
||||
debug!("normalize_provider(goal={:#?})", goal);
|
||||
|
||||
tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed);
|
||||
tcx.infer_ctxt().enter_canonical_trait_query(
|
||||
&goal,
|
||||
|ocx, ParamEnvAnd { param_env, value: goal }| {
|
||||
let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.substs).map(
|
||||
|(predicate, span)| {
|
||||
traits::Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::dummy_with_span(span),
|
||||
param_env,
|
||||
predicate,
|
||||
)
|
||||
},
|
||||
);
|
||||
ocx.register_obligations(obligations);
|
||||
let normalized_ty = tcx.type_of(goal.def_id).subst(tcx, goal.substs);
|
||||
Ok(NormalizationResult { normalized_ty })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn normalize_inherent_projection_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalProjectionGoal<'tcx>,
|
||||
|
|
|
|||
|
|
@ -177,85 +177,6 @@ fn resolve_associated_item<'tcx>(
|
|||
|
||||
Some(ty::Instance::new(leaf_def.item.def_id, substs))
|
||||
}
|
||||
traits::ImplSource::Generator(generator_data) => {
|
||||
if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
|
||||
// For compiler developers who'd like to add new items to `Generator`,
|
||||
// you either need to generate a shim body, or perhaps return
|
||||
// `InstanceDef::Item` pointing to a trait default method body if
|
||||
// it is given a default implementation by the trait.
|
||||
span_bug!(
|
||||
tcx.def_span(generator_data.generator_def_id),
|
||||
"no definition for `{trait_ref}::{}` for built-in generator type",
|
||||
tcx.item_name(trait_item_id)
|
||||
)
|
||||
}
|
||||
Some(Instance {
|
||||
def: ty::InstanceDef::Item(generator_data.generator_def_id),
|
||||
substs: generator_data.substs,
|
||||
})
|
||||
}
|
||||
traits::ImplSource::Future(future_data) => {
|
||||
if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
|
||||
// `Future::poll` is generated by the compiler.
|
||||
Some(Instance {
|
||||
def: ty::InstanceDef::Item(future_data.generator_def_id),
|
||||
substs: future_data.substs,
|
||||
})
|
||||
} else {
|
||||
// All other methods are default methods of the `Future` trait.
|
||||
// (this assumes that `ImplSource::Future` is only used for methods on `Future`)
|
||||
debug_assert!(tcx.defaultness(trait_item_id).has_value());
|
||||
Some(Instance::new(trait_item_id, rcvr_substs))
|
||||
}
|
||||
}
|
||||
traits::ImplSource::Closure(closure_data) => {
|
||||
if cfg!(debug_assertions)
|
||||
&& ![sym::call, sym::call_mut, sym::call_once]
|
||||
.contains(&tcx.item_name(trait_item_id))
|
||||
{
|
||||
// For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
|
||||
// you either need to generate a shim body, or perhaps return
|
||||
// `InstanceDef::Item` pointing to a trait default method body if
|
||||
// it is given a default implementation by the trait.
|
||||
span_bug!(
|
||||
tcx.def_span(closure_data.closure_def_id),
|
||||
"no definition for `{trait_ref}::{}` for built-in closure type",
|
||||
tcx.item_name(trait_item_id)
|
||||
)
|
||||
}
|
||||
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
|
||||
Instance::resolve_closure(
|
||||
tcx,
|
||||
closure_data.closure_def_id,
|
||||
closure_data.substs,
|
||||
trait_closure_kind,
|
||||
)
|
||||
}
|
||||
traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
|
||||
ty::FnDef(..) | ty::FnPtr(..) => {
|
||||
if cfg!(debug_assertions)
|
||||
&& ![sym::call, sym::call_mut, sym::call_once]
|
||||
.contains(&tcx.item_name(trait_item_id))
|
||||
{
|
||||
// For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
|
||||
// you either need to generate a shim body, or perhaps return
|
||||
// `InstanceDef::Item` pointing to a trait default method body if
|
||||
// it is given a default implementation by the trait.
|
||||
bug!(
|
||||
"no definition for `{trait_ref}::{}` for built-in fn type",
|
||||
tcx.item_name(trait_item_id)
|
||||
)
|
||||
}
|
||||
Some(Instance {
|
||||
def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
|
||||
substs: rcvr_substs,
|
||||
})
|
||||
}
|
||||
_ => bug!(
|
||||
"no built-in definition for `{trait_ref}::{}` for non-fn type",
|
||||
tcx.item_name(trait_item_id)
|
||||
),
|
||||
},
|
||||
traits::ImplSource::Object(ref data) => {
|
||||
traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
|
||||
Instance {
|
||||
|
|
@ -308,15 +229,73 @@ fn resolve_associated_item<'tcx>(
|
|||
span: tcx.def_span(trait_item_id),
|
||||
})
|
||||
}
|
||||
} else if Some(trait_ref.def_id) == lang_items.future_trait() {
|
||||
let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else {
|
||||
bug!()
|
||||
};
|
||||
if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
|
||||
// `Future::poll` is generated by the compiler.
|
||||
Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs: substs })
|
||||
} else {
|
||||
// All other methods are default methods of the `Future` trait.
|
||||
// (this assumes that `ImplSource::Builtin` is only used for methods on `Future`)
|
||||
debug_assert!(tcx.defaultness(trait_item_id).has_value());
|
||||
Some(Instance::new(trait_item_id, rcvr_substs))
|
||||
}
|
||||
} else if Some(trait_ref.def_id) == lang_items.gen_trait() {
|
||||
let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else {
|
||||
bug!()
|
||||
};
|
||||
if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
|
||||
// For compiler developers who'd like to add new items to `Generator`,
|
||||
// you either need to generate a shim body, or perhaps return
|
||||
// `InstanceDef::Item` pointing to a trait default method body if
|
||||
// it is given a default implementation by the trait.
|
||||
span_bug!(
|
||||
tcx.def_span(generator_def_id),
|
||||
"no definition for `{trait_ref}::{}` for built-in generator type",
|
||||
tcx.item_name(trait_item_id)
|
||||
)
|
||||
}
|
||||
Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs })
|
||||
} else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() {
|
||||
// FIXME: This doesn't check for malformed libcore that defines, e.g.,
|
||||
// `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension
|
||||
// methods.
|
||||
if cfg!(debug_assertions)
|
||||
&& ![sym::call, sym::call_mut, sym::call_once]
|
||||
.contains(&tcx.item_name(trait_item_id))
|
||||
{
|
||||
// For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
|
||||
// you either need to generate a shim body, or perhaps return
|
||||
// `InstanceDef::Item` pointing to a trait default method body if
|
||||
// it is given a default implementation by the trait.
|
||||
bug!(
|
||||
"no definition for `{trait_ref}::{}` for built-in callable type",
|
||||
tcx.item_name(trait_item_id)
|
||||
)
|
||||
}
|
||||
match *rcvr_substs.type_at(0).kind() {
|
||||
ty::Closure(closure_def_id, substs) => {
|
||||
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
|
||||
Instance::resolve_closure(tcx, closure_def_id, substs, trait_closure_kind)
|
||||
}
|
||||
ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
|
||||
def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_substs.type_at(0)),
|
||||
substs: rcvr_substs,
|
||||
}),
|
||||
_ => bug!(
|
||||
"no built-in definition for `{trait_ref}::{}` for non-fn type",
|
||||
tcx.item_name(trait_item_id)
|
||||
),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
traits::ImplSource::AutoImpl(..)
|
||||
| traits::ImplSource::Param(..)
|
||||
traits::ImplSource::Param(..)
|
||||
| traits::ImplSource::TraitAlias(..)
|
||||
| traits::ImplSource::TraitUpcasting(_)
|
||||
| traits::ImplSource::ConstDestruct(_) => None,
|
||||
| traits::ImplSource::TraitUpcasting(_) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,17 @@ pub enum DynKind {
|
|||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum AliasKind {
|
||||
/// A projection `<Type as Trait>::AssocType`.
|
||||
/// Can get normalized away if monomorphic enough.
|
||||
Projection,
|
||||
Inherent,
|
||||
/// An opaque type (usually from `impl Trait` in type aliases or function return types)
|
||||
/// Can only be normalized away in RevealAll mode
|
||||
Opaque,
|
||||
/// A type alias that actually checks its trait bounds.
|
||||
/// Currently only used if the type alias references opaque types.
|
||||
/// Can always be normalized away.
|
||||
Weak,
|
||||
}
|
||||
|
||||
/// Defines the kinds of types used by the type system.
|
||||
|
|
|
|||
|
|
@ -56,6 +56,11 @@
|
|||
//! [`Rc`]: rc
|
||||
//! [`RefCell`]: core::cell
|
||||
|
||||
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||
// rustc itself never sets the feature, so this line has no affect there.
|
||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||
//
|
||||
#![allow(unused_attributes)]
|
||||
#![stable(feature = "alloc", since = "1.36.0")]
|
||||
#![doc(
|
||||
|
|
@ -75,11 +80,6 @@
|
|||
))]
|
||||
#![no_std]
|
||||
#![needs_allocator]
|
||||
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||
// rustc itself never sets the feature, so this line has no affect there.
|
||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||
//
|
||||
// Lints:
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(fuzzy_provenance_casts)]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ use crate::ptr::NonNull;
|
|||
)]
|
||||
#[doc(hidden)]
|
||||
#[repr(transparent)]
|
||||
// Lang item used experimentally by Miri to define the semantics of `Unique`.
|
||||
#[cfg_attr(not(bootstrap), lang = "ptr_unique")]
|
||||
pub struct Unique<T: ?Sized> {
|
||||
pointer: NonNull<T>,
|
||||
// NOTE: this marker has no consequences for variance, but is necessary
|
||||
|
|
|
|||
|
|
@ -47,9 +47,9 @@ use buffer::Buffer;
|
|||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct BufReader<R> {
|
||||
inner: R,
|
||||
pub struct BufReader<R: ?Sized> {
|
||||
buf: Buffer,
|
||||
inner: R,
|
||||
}
|
||||
|
||||
impl<R: Read> BufReader<R> {
|
||||
|
|
@ -95,7 +95,7 @@ impl<R: Read> BufReader<R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> BufReader<R> {
|
||||
impl<R: ?Sized> BufReader<R> {
|
||||
/// Gets a reference to the underlying reader.
|
||||
///
|
||||
/// It is inadvisable to directly read from the underlying reader.
|
||||
|
|
@ -213,7 +213,10 @@ impl<R> BufReader<R> {
|
|||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_inner(self) -> R {
|
||||
pub fn into_inner(self) -> R
|
||||
where
|
||||
R: Sized,
|
||||
{
|
||||
self.inner
|
||||
}
|
||||
|
||||
|
|
@ -226,13 +229,13 @@ impl<R> BufReader<R> {
|
|||
|
||||
// This is only used by a test which asserts that the initialization-tracking is correct.
|
||||
#[cfg(test)]
|
||||
impl<R> BufReader<R> {
|
||||
impl<R: ?Sized> BufReader<R> {
|
||||
pub fn initialized(&self) -> usize {
|
||||
self.buf.initialized()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Seek> BufReader<R> {
|
||||
impl<R: ?Sized + Seek> BufReader<R> {
|
||||
/// Seeks relative to the current position. If the new position lies within the buffer,
|
||||
/// the buffer will not be flushed, allowing for more efficient seeks.
|
||||
/// This method does not return the location of the underlying reader, so the caller
|
||||
|
|
@ -257,7 +260,7 @@ impl<R: Seek> BufReader<R> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<R: Read> Read for BufReader<R> {
|
||||
impl<R: ?Sized + Read> Read for BufReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// If we don't have any buffered data and we're doing a massive read
|
||||
// (larger than our internal buffer), bypass our internal buffer
|
||||
|
|
@ -371,7 +374,7 @@ impl<R: Read> Read for BufReader<R> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<R: Read> BufRead for BufReader<R> {
|
||||
impl<R: ?Sized + Read> BufRead for BufReader<R> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
self.buf.fill_buf(&mut self.inner)
|
||||
}
|
||||
|
|
@ -384,11 +387,11 @@ impl<R: Read> BufRead for BufReader<R> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<R> fmt::Debug for BufReader<R>
|
||||
where
|
||||
R: fmt::Debug,
|
||||
R: ?Sized + fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("BufReader")
|
||||
.field("reader", &self.inner)
|
||||
.field("reader", &&self.inner)
|
||||
.field(
|
||||
"buffer",
|
||||
&format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
|
||||
|
|
@ -398,7 +401,7 @@ where
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<R: Seek> Seek for BufReader<R> {
|
||||
impl<R: ?Sized + Seek> Seek for BufReader<R> {
|
||||
/// Seek to an offset, in bytes, in the underlying reader.
|
||||
///
|
||||
/// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
|
||||
|
|
@ -491,7 +494,7 @@ impl<R: Seek> Seek for BufReader<R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> SizeHint for BufReader<T> {
|
||||
impl<T: ?Sized> SizeHint for BufReader<T> {
|
||||
#[inline]
|
||||
fn lower_bound(&self) -> usize {
|
||||
SizeHint::lower_bound(self.get_ref()) + self.buffer().len()
|
||||
|
|
|
|||
|
|
@ -67,8 +67,7 @@ use crate::ptr;
|
|||
/// [`TcpStream`]: crate::net::TcpStream
|
||||
/// [`flush`]: BufWriter::flush
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct BufWriter<W: Write> {
|
||||
inner: W,
|
||||
pub struct BufWriter<W: ?Sized + Write> {
|
||||
// The buffer. Avoid using this like a normal `Vec` in common code paths.
|
||||
// That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
|
||||
// methods that require bounds checking or the like. This makes an enormous
|
||||
|
|
@ -78,6 +77,7 @@ pub struct BufWriter<W: Write> {
|
|||
// write the buffered data a second time in BufWriter's destructor. This
|
||||
// flag tells the Drop impl if it should skip the flush.
|
||||
panicked: bool,
|
||||
inner: W,
|
||||
}
|
||||
|
||||
impl<W: Write> BufWriter<W> {
|
||||
|
|
@ -115,6 +115,69 @@ impl<W: Write> BufWriter<W> {
|
|||
BufWriter { inner, buf: Vec::with_capacity(capacity), panicked: false }
|
||||
}
|
||||
|
||||
/// Unwraps this `BufWriter<W>`, returning the underlying writer.
|
||||
///
|
||||
/// The buffer is written out before returning the writer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// An [`Err`] will be returned if an error occurs while flushing the buffer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io::BufWriter;
|
||||
/// use std::net::TcpStream;
|
||||
///
|
||||
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
|
||||
///
|
||||
/// // unwrap the TcpStream and flush the buffer
|
||||
/// let stream = buffer.into_inner().unwrap();
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
|
||||
match self.flush_buf() {
|
||||
Err(e) => Err(IntoInnerError::new(self, e)),
|
||||
Ok(()) => Ok(self.into_parts().0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
|
||||
/// unwritten data.
|
||||
///
|
||||
/// If the underlying writer panicked, it is not known what portion of the data was written.
|
||||
/// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
|
||||
/// contents can still be recovered).
|
||||
///
|
||||
/// `into_parts` makes no attempt to flush data and cannot fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::{BufWriter, Write};
|
||||
///
|
||||
/// let mut buffer = [0u8; 10];
|
||||
/// let mut stream = BufWriter::new(buffer.as_mut());
|
||||
/// write!(stream, "too much data").unwrap();
|
||||
/// stream.flush().expect_err("it doesn't fit");
|
||||
/// let (recovered_writer, buffered_data) = stream.into_parts();
|
||||
/// assert_eq!(recovered_writer.len(), 0);
|
||||
/// assert_eq!(&buffered_data.unwrap(), b"ata");
|
||||
/// ```
|
||||
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
|
||||
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
|
||||
let buf = mem::take(&mut self.buf);
|
||||
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
|
||||
|
||||
// SAFETY: forget(self) prevents double dropping inner
|
||||
let inner = unsafe { ptr::read(&self.inner) };
|
||||
mem::forget(self);
|
||||
|
||||
(inner, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: ?Sized + Write> BufWriter<W> {
|
||||
/// Send data in our local buffer into the inner writer, looping as
|
||||
/// necessary until either it's all been sent or an error occurs.
|
||||
///
|
||||
|
|
@ -284,67 +347,6 @@ impl<W: Write> BufWriter<W> {
|
|||
self.buf.capacity()
|
||||
}
|
||||
|
||||
/// Unwraps this `BufWriter<W>`, returning the underlying writer.
|
||||
///
|
||||
/// The buffer is written out before returning the writer.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// An [`Err`] will be returned if an error occurs while flushing the buffer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::io::BufWriter;
|
||||
/// use std::net::TcpStream;
|
||||
///
|
||||
/// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
|
||||
///
|
||||
/// // unwrap the TcpStream and flush the buffer
|
||||
/// let stream = buffer.into_inner().unwrap();
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
|
||||
match self.flush_buf() {
|
||||
Err(e) => Err(IntoInnerError::new(self, e)),
|
||||
Ok(()) => Ok(self.into_parts().0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Disassembles this `BufWriter<W>`, returning the underlying writer, and any buffered but
|
||||
/// unwritten data.
|
||||
///
|
||||
/// If the underlying writer panicked, it is not known what portion of the data was written.
|
||||
/// In this case, we return `WriterPanicked` for the buffered data (from which the buffer
|
||||
/// contents can still be recovered).
|
||||
///
|
||||
/// `into_parts` makes no attempt to flush data and cannot fail.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::{BufWriter, Write};
|
||||
///
|
||||
/// let mut buffer = [0u8; 10];
|
||||
/// let mut stream = BufWriter::new(buffer.as_mut());
|
||||
/// write!(stream, "too much data").unwrap();
|
||||
/// stream.flush().expect_err("it doesn't fit");
|
||||
/// let (recovered_writer, buffered_data) = stream.into_parts();
|
||||
/// assert_eq!(recovered_writer.len(), 0);
|
||||
/// assert_eq!(&buffered_data.unwrap(), b"ata");
|
||||
/// ```
|
||||
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
|
||||
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
|
||||
let buf = mem::take(&mut self.buf);
|
||||
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
|
||||
|
||||
// SAFETY: forget(self) prevents double dropping inner
|
||||
let inner = unsafe { ptr::read(&self.inner) };
|
||||
mem::forget(self);
|
||||
|
||||
(inner, buf)
|
||||
}
|
||||
|
||||
// Ensure this function does not get inlined into `write`, so that it
|
||||
// remains inlineable and its common path remains as short as possible.
|
||||
// If this function ends up being called frequently relative to `write`,
|
||||
|
|
@ -511,7 +513,7 @@ impl fmt::Debug for WriterPanicked {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write> Write for BufWriter<W> {
|
||||
impl<W: ?Sized + Write> Write for BufWriter<W> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// Use < instead of <= to avoid a needless trip through the buffer in some cases.
|
||||
|
|
@ -640,20 +642,20 @@ impl<W: Write> Write for BufWriter<W> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write> fmt::Debug for BufWriter<W>
|
||||
impl<W: ?Sized + Write> fmt::Debug for BufWriter<W>
|
||||
where
|
||||
W: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("BufWriter")
|
||||
.field("writer", &self.inner)
|
||||
.field("writer", &&self.inner)
|
||||
.field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write + Seek> Seek for BufWriter<W> {
|
||||
impl<W: ?Sized + Write + Seek> Seek for BufWriter<W> {
|
||||
/// Seek to the offset, in bytes, in the underlying writer.
|
||||
///
|
||||
/// Seeking always writes out the internal buffer before seeking.
|
||||
|
|
@ -664,7 +666,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write> Drop for BufWriter<W> {
|
||||
impl<W: ?Sized + Write> Drop for BufWriter<W> {
|
||||
fn drop(&mut self) {
|
||||
if !self.panicked {
|
||||
// dtors should not panic, so we ignore a failed flush
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSli
|
|||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct LineWriter<W: Write> {
|
||||
pub struct LineWriter<W: ?Sized + Write> {
|
||||
inner: BufWriter<W>,
|
||||
}
|
||||
|
||||
|
|
@ -109,27 +109,6 @@ impl<W: Write> LineWriter<W> {
|
|||
LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
|
||||
}
|
||||
|
||||
/// Gets a reference to the underlying writer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::LineWriter;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let file = File::create("poem.txt")?;
|
||||
/// let file = LineWriter::new(file);
|
||||
///
|
||||
/// let reference = file.get_ref();
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get_ref(&self) -> &W {
|
||||
self.inner.get_ref()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the underlying writer.
|
||||
///
|
||||
/// Caution must be taken when calling methods on the mutable reference
|
||||
|
|
@ -184,8 +163,31 @@ impl<W: Write> LineWriter<W> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<W: ?Sized + Write> LineWriter<W> {
|
||||
/// Gets a reference to the underlying writer.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::LineWriter;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let file = File::create("poem.txt")?;
|
||||
/// let file = LineWriter::new(file);
|
||||
///
|
||||
/// let reference = file.get_ref();
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get_ref(&self) -> &W {
|
||||
self.inner.get_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write> Write for LineWriter<W> {
|
||||
impl<W: ?Sized + Write> Write for LineWriter<W> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
LineWriterShim::new(&mut self.inner).write(buf)
|
||||
}
|
||||
|
|
@ -216,7 +218,7 @@ impl<W: Write> Write for LineWriter<W> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W: Write> fmt::Debug for LineWriter<W>
|
||||
impl<W: ?Sized + Write> fmt::Debug for LineWriter<W>
|
||||
where
|
||||
W: fmt::Debug,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ use crate::sys_common::memchr;
|
|||
/// `BufWriters` to be temporarily given line-buffering logic; this is what
|
||||
/// enables Stdout to be alternately in line-buffered or block-buffered mode.
|
||||
#[derive(Debug)]
|
||||
pub struct LineWriterShim<'a, W: Write> {
|
||||
pub struct LineWriterShim<'a, W: ?Sized + Write> {
|
||||
buffer: &'a mut BufWriter<W>,
|
||||
}
|
||||
|
||||
impl<'a, W: Write> LineWriterShim<'a, W> {
|
||||
impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
|
||||
pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ impl<'a, W: Write> LineWriterShim<'a, W> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, W: Write> Write for LineWriterShim<'a, W> {
|
||||
impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
|
||||
/// Write some data into this BufReader with line buffering. This means
|
||||
/// that, if any newlines are present in the data, the data up to the last
|
||||
/// newline is sent directly to the underlying writer, and data after it
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ impl<W: Write + ?Sized> BufferedCopySpec for W {
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Write> BufferedCopySpec for BufWriter<I> {
|
||||
impl<I: ?Sized + Write> BufferedCopySpec for BufWriter<I> {
|
||||
fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> {
|
||||
if writer.capacity() < DEFAULT_BUF_SIZE {
|
||||
return stack_buffer_copy(reader, writer);
|
||||
|
|
|
|||
|
|
@ -2754,7 +2754,7 @@ trait SizeHint {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> SizeHint for T {
|
||||
impl<T: ?Sized> SizeHint for T {
|
||||
#[inline]
|
||||
default fn lower_bound(&self) -> usize {
|
||||
0
|
||||
|
|
|
|||
|
|
@ -188,6 +188,13 @@
|
|||
//! [array]: prim@array
|
||||
//! [slice]: prim@slice
|
||||
|
||||
// To run std tests without x.py without ending up with two copies of std, Miri needs to be
|
||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||
// rustc itself never sets the feature, so this line has no affect there.
|
||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||
// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
|
||||
#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
|
||||
//
|
||||
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
|
||||
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
|
||||
#![doc(
|
||||
|
|
@ -202,12 +209,6 @@
|
|||
no_global_oom_handling,
|
||||
not(no_global_oom_handling)
|
||||
))]
|
||||
// To run std tests without x.py without ending up with two copies of std, Miri needs to be
|
||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||
// rustc itself never sets the feature, so this line has no affect there.
|
||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||
// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
|
||||
#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
|
||||
// Don't link to std. We are std.
|
||||
#![no_std]
|
||||
// Tell the compiler to link to either panic_abort or panic_unwind
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ mod libc {
|
|||
pub use libc::c_int;
|
||||
pub struct ucred;
|
||||
pub struct cmsghdr;
|
||||
pub struct sockcred2;
|
||||
pub type pid_t = i32;
|
||||
pub type gid_t = u32;
|
||||
pub type uid_t = u32;
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ impl<T: CopyRead> CopyRead for Take<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: CopyRead> CopyRead for BufReader<T> {
|
||||
impl<T: ?Sized + CopyRead> CopyRead for BufReader<T> {
|
||||
fn drain_to<W: Write>(&mut self, writer: &mut W, outer_limit: u64) -> Result<u64> {
|
||||
let buf = self.buffer();
|
||||
let buf = &buf[0..min(buf.len(), outer_limit.try_into().unwrap_or(usize::MAX))];
|
||||
|
|
@ -495,7 +495,7 @@ impl<T: CopyRead> CopyRead for BufReader<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: CopyWrite> CopyWrite for BufWriter<T> {
|
||||
impl<T: ?Sized + CopyWrite> CopyWrite for BufWriter<T> {
|
||||
fn properties(&self) -> CopyParams {
|
||||
self.get_ref().properties()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -344,6 +344,29 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
{
|
||||
unsafe {
|
||||
let set = libc::_cpuset_create();
|
||||
if !set.is_null() {
|
||||
let mut count: usize = 0;
|
||||
if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 {
|
||||
for i in 0..u64::MAX {
|
||||
match libc::_cpuset_isset(i, set) {
|
||||
-1 => break,
|
||||
0 => continue,
|
||||
_ => count = count + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
libc::_cpuset_destroy(set);
|
||||
if let Some(count) = NonZeroUsize::new(count) {
|
||||
return Ok(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut cpus: libc::c_uint = 0;
|
||||
let mut cpus_size = crate::mem::size_of_val(&cpus);
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
|
|||
python3 ../x.py test --stage 0 src/tools/compiletest && \
|
||||
python3 ../x.py test --stage 0 core alloc std test proc_macro && \
|
||||
# Build both public and internal documentation.
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library && \
|
||||
mkdir -p /checkout/obj/staging/doc && \
|
||||
cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
|
||||
/scripts/validate-toolstate.sh && \
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ x--expand-yaml-anchors--remove:
|
|||
- &shared-ci-variables
|
||||
CI_JOB_NAME: ${{ matrix.name }}
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||
# commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs.
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- &public-variables
|
||||
SCCACHE_BUCKET: rust-lang-ci-sccache2
|
||||
|
|
@ -229,6 +231,20 @@ x--expand-yaml-anchors--remove:
|
|||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
<<: *step
|
||||
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
<<: *step
|
||||
|
||||
- name: upload artifacts to github
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
# name is set in previous step
|
||||
name: ${{ env.DOC_ARTIFACT_NAME }}
|
||||
path: obj/artifacts/doc
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
<<: *step
|
||||
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
env:
|
||||
|
|
|
|||
42
src/ci/scripts/create-doc-artifacts.sh
Executable file
42
src/ci/scripts/create-doc-artifacts.sh
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash
|
||||
# Compress doc artifacts and name them based on the commit, or the date if
|
||||
# commit is not available.
|
||||
|
||||
set -euox pipefail
|
||||
|
||||
# Try to get short commit hash, fallback to date
|
||||
if [ -n "$HEAD_SHA" ]; then
|
||||
short_rev=$(echo "${HEAD_SHA}" | cut -c1-8)
|
||||
else
|
||||
short_rev=$(git rev-parse --short HEAD || date -u +'%Y-%m-%dT%H%M%SZ')
|
||||
fi
|
||||
|
||||
# Try to get branch, fallback to none
|
||||
branch=$(git branch --show-current || echo)
|
||||
|
||||
if [ -n "$branch" ]; then
|
||||
branch="${branch}-"
|
||||
fi
|
||||
|
||||
if [ "${GITHUB_EVENT_NAME:=none}" = "pull_request" ]; then
|
||||
pr_num=$(echo "$GITHUB_REF_NAME" | cut -d'/' -f1)
|
||||
name="doc-${pr_num}-${short_rev}"
|
||||
else
|
||||
name="doc-${branch}${short_rev}"
|
||||
fi
|
||||
|
||||
|
||||
if [ -d "obj/staging/doc" ]; then
|
||||
mkdir -p obj/artifacts/doc
|
||||
|
||||
# Level 12 seems to give a good tradeoff of time vs. space savings
|
||||
ZSTD_CLEVEL=12 ZSTD_NBTHREADS=4 \
|
||||
tar --zstd -cf "obj/artifacts/doc/${name}.tar.zst" -C obj/staging/doc .
|
||||
|
||||
ls -lh obj/artifacts/doc
|
||||
fi
|
||||
|
||||
# Set this environment variable for future use if running in CI
|
||||
if [ -n "$GITHUB_ENV" ]; then
|
||||
echo "DOC_ARTIFACT_NAME=${name}" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
|
@ -2052,6 +2052,11 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
}))
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, data) => {
|
||||
let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs);
|
||||
clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
|
||||
}
|
||||
|
||||
ty::Param(ref p) => {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||
ImplTrait(bounds)
|
||||
|
|
|
|||
|
|
@ -800,10 +800,11 @@ fn assoc_type(
|
|||
if !bounds.is_empty() {
|
||||
write!(w, ": {}", print_generic_bounds(bounds, cx))
|
||||
}
|
||||
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
||||
// Render the default before the where-clause which aligns with the new recommended style. See #89122.
|
||||
if let Some(default) = default {
|
||||
write!(w, " = {}", default.print(cx))
|
||||
}
|
||||
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
||||
}
|
||||
|
||||
fn assoc_method(
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ a.anchor,
|
|||
h1 a,
|
||||
.search-results a,
|
||||
.stab,
|
||||
.result-name .primitive > i, .result-name .keyword > i {
|
||||
.result-name i {
|
||||
color: var(--main-color);
|
||||
}
|
||||
|
||||
|
|
@ -887,7 +887,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
|||
.search-results .result-name span.alias {
|
||||
color: var(--search-results-alias-color);
|
||||
}
|
||||
.search-results .result-name span.grey {
|
||||
.search-results .result-name .grey {
|
||||
color: var(--search-results-grey-color);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,35 @@ const itemTypes = [
|
|||
"traitalias",
|
||||
];
|
||||
|
||||
const longItemTypes = [
|
||||
"module",
|
||||
"extern crate",
|
||||
"re-export",
|
||||
"struct",
|
||||
"enum",
|
||||
"function",
|
||||
"type alias",
|
||||
"static",
|
||||
"trait",
|
||||
"",
|
||||
"trait method",
|
||||
"method",
|
||||
"struct field",
|
||||
"enum variant",
|
||||
"macro",
|
||||
"primitive type",
|
||||
"associated type",
|
||||
"constant",
|
||||
"associated constant",
|
||||
"union",
|
||||
"foreign type",
|
||||
"keyword",
|
||||
"existential type",
|
||||
"attribute macro",
|
||||
"derive macro",
|
||||
"trait alias",
|
||||
];
|
||||
|
||||
// used for special search precedence
|
||||
const TY_PRIMITIVE = itemTypes.indexOf("primitive");
|
||||
const TY_KEYWORD = itemTypes.indexOf("keyword");
|
||||
|
|
@ -1966,16 +1995,11 @@ function initSearch(rawSearchIndex) {
|
|||
array.forEach(item => {
|
||||
const name = item.name;
|
||||
const type = itemTypes[item.ty];
|
||||
const longType = longItemTypes[item.ty];
|
||||
const typeName = longType.length !== 0 ? `${longType}` : "?";
|
||||
|
||||
length += 1;
|
||||
|
||||
let extra = "";
|
||||
if (type === "primitive") {
|
||||
extra = " <i>(primitive type)</i>";
|
||||
} else if (type === "keyword") {
|
||||
extra = " <i>(keyword)</i>";
|
||||
}
|
||||
|
||||
const link = document.createElement("a");
|
||||
link.className = "result-" + type;
|
||||
link.href = item.href;
|
||||
|
|
@ -1993,13 +2017,14 @@ function initSearch(rawSearchIndex) {
|
|||
|
||||
alias.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
"<span class=\"grey\"><i> - see </i></span>");
|
||||
"<i class=\"grey\"> - see </i>");
|
||||
|
||||
resultName.appendChild(alias);
|
||||
}
|
||||
|
||||
resultName.insertAdjacentHTML(
|
||||
"beforeend",
|
||||
item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
|
||||
`${typeName} ${item.displayPath}<span class="${type}">${name}</span>`);
|
||||
link.appendChild(resultName);
|
||||
|
||||
const description = document.createElement("div");
|
||||
|
|
|
|||
|
|
@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>(
|
|||
continue;
|
||||
},
|
||||
ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
|
||||
ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"),
|
||||
ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
|
||||
ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
|
||||
TyPosition::new_deref_stable_for_result(precedence, ty)
|
||||
|
|
|
|||
|
|
@ -82,10 +82,4 @@ fn msrv_1_41() {
|
|||
}
|
||||
}
|
||||
|
||||
type Opaque = impl Sized;
|
||||
struct IntoOpaque;
|
||||
impl Into<Opaque> for IntoOpaque {
|
||||
fn into(self) -> Opaque {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -82,10 +82,4 @@ fn msrv_1_41() {
|
|||
}
|
||||
}
|
||||
|
||||
type Opaque = impl Sized;
|
||||
struct IntoOpaque;
|
||||
impl Into<Opaque> for IntoOpaque {
|
||||
fn into(self) -> Opaque {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,10 @@ impl Into<u8> for ContainsVal {
|
|||
}
|
||||
}
|
||||
|
||||
type Opaque = impl Sized;
|
||||
struct IntoOpaque;
|
||||
impl Into<Opaque> for IntoOpaque {
|
||||
fn into(self) -> Opaque {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,12 @@
|
|||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into_unfixable.rs:11:1
|
||||
error[E0658]: `impl Trait` in type aliases is unstable
|
||||
--> $DIR/from_over_into_unfixable.rs:35:15
|
||||
|
|
||||
LL | impl Into<InMacro> for String {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | type Opaque = impl Sized;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= help: replace the `Into` implementation with `From<std::string::String>`
|
||||
= note: `-D clippy::from-over-into` implied by `-D warnings`
|
||||
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
|
||||
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
|
||||
|
||||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into_unfixable.rs:19:1
|
||||
|
|
||||
LL | impl Into<WeirdUpperSelf> for &'static [u8] {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: replace the `Into` implementation with `From<&'static [u8]>`
|
||||
|
||||
error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
|
||||
--> $DIR/from_over_into_unfixable.rs:28:1
|
||||
|
|
||||
LL | impl Into<u8> for ContainsVal {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
|
||||
https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
|
||||
= help: replace the `Into` implementation with `From<ContainsVal>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -401,25 +401,3 @@ mod issue7344 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod issue10041 {
|
||||
struct Bomb;
|
||||
|
||||
impl Bomb {
|
||||
// Hidden <Rhs = Self> default generic parameter.
|
||||
pub fn new() -> impl PartialOrd {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
|
||||
// TAIT with self-referencing bounds
|
||||
type X = impl std::ops::Add<Output = X>;
|
||||
|
||||
struct Bomb2;
|
||||
|
||||
impl Bomb2 {
|
||||
pub fn new() -> X {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,21 +92,5 @@ LL | | unimplemented!()
|
|||
LL | | }
|
||||
| |_________^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:410:9
|
||||
|
|
||||
LL | / pub fn new() -> impl PartialOrd {
|
||||
LL | | 0i32
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
||||
error: methods called `new` usually return `Self`
|
||||
--> $DIR/new_ret_no_self.rs:421:9
|
||||
|
|
||||
LL | / pub fn new() -> X {
|
||||
LL | | 0i32
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
|
|||
26
src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs
Normal file
26
src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![warn(clippy::new_ret_no_self)]
|
||||
|
||||
mod issue10041 {
|
||||
struct Bomb;
|
||||
|
||||
impl Bomb {
|
||||
// Hidden <Rhs = Self> default generic parameter.
|
||||
pub fn new() -> impl PartialOrd {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
|
||||
// TAIT with self-referencing bounds
|
||||
type X = impl std::ops::Add<Output = X>;
|
||||
|
||||
struct Bomb2;
|
||||
|
||||
impl Bomb2 {
|
||||
pub fn new() -> X {
|
||||
0i32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0275]: overflow evaluating the requirement `<i32 as std::ops::Add>::Output == issue10041::X`
|
||||
--> $DIR/new_ret_no_self_overflow.rs:20:25
|
||||
|
|
||||
LL | pub fn new() -> X {
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
//@compile-flags: -Zmir-opt-level=3
|
||||
//@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000
|
||||
// Enable MIR inlining to ensure that `TerminatorKind::Terminate` is generated
|
||||
// instead of just `UnwindAction::Terminate`.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
// compile-flags: -g -C no-prepopulate-passes
|
||||
|
||||
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_variant_part,{{.*}}size: 32,{{.*}}
|
||||
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}}
|
||||
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}}
|
||||
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i128 4294967295{{[,)].*}}
|
||||
// CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i128 0{{[,)].*}}
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
|
|
|
|||
27
tests/codegen/enum-u128.rs
Normal file
27
tests/codegen/enum-u128.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// This tests that debug info for "c-like" 128bit enums is properly emitted.
|
||||
// This is ignored for the fallback mode on MSVC due to problems with PDB.
|
||||
|
||||
//
|
||||
// ignore-msvc
|
||||
|
||||
// compile-flags: -g -C no-prepopulate-passes
|
||||
|
||||
// CHECK-LABEL: @main
|
||||
// CHECK: {{.*}}DICompositeType{{.*}}tag: DW_TAG_enumeration_type,{{.*}}name: "Foo",{{.*}}flags: DIFlagEnumClass,{{.*}}
|
||||
// CHECK: {{.*}}DIEnumerator{{.*}}name: "Lo",{{.*}}value: 0,{{.*}}
|
||||
// CHECK: {{.*}}DIEnumerator{{.*}}name: "Hi",{{.*}}value: 18446744073709551616,{{.*}}
|
||||
// CHECK: {{.*}}DIEnumerator{{.*}}name: "Bar",{{.*}}value: 18446745000000000123,{{.*}}
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(repr128)]
|
||||
|
||||
#[repr(u128)]
|
||||
pub enum Foo {
|
||||
Lo,
|
||||
Hi = 1 << 64,
|
||||
Bar = 18_446_745_000_000_000_123,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let foo = Foo::Bar;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
//
|
||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
// needs-asm-support
|
||||
// compile-flags: -Zinline-mir-hint-threshold=1000
|
||||
#![feature(asm_unwind)]
|
||||
|
||||
struct D;
|
||||
|
|
@ -10,7 +11,7 @@ impl Drop for D {
|
|||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn foo() {
|
||||
let _d = D;
|
||||
unsafe { std::arch::asm!("", options(may_unwind)) };
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
// compile-flags: -Zinline-mir-hint-threshold=1000
|
||||
|
||||
// EMIT_MIR cycle.f.Inline.diff
|
||||
#[inline(always)]
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue