mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
544b4cfe4d
commit
dbf04a5ee2
106 changed files with 2219 additions and 609 deletions
|
@ -12,7 +12,7 @@ use hir_def::{
|
|||
use crate::{
|
||||
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
|
||||
from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders,
|
||||
CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
|
||||
CallableDefId, CallableSig, DynTy, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
|
||||
QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
|
||||
};
|
||||
|
||||
|
@ -378,6 +378,19 @@ impl ProjectionTyExt for ProjectionTy {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait DynTyExt {
|
||||
fn principal(&self) -> Option<&TraitRef>;
|
||||
}
|
||||
|
||||
impl DynTyExt for DynTy {
|
||||
fn principal(&self) -> Option<&TraitRef> {
|
||||
self.bounds.skip_binders().interned().get(0).and_then(|b| match b.skip_binders() {
|
||||
crate::WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TraitRefExt {
|
||||
fn hir_trait_id(&self) -> TraitId;
|
||||
}
|
||||
|
|
|
@ -11,3 +11,9 @@ pub use crate::diagnostics::{
|
|||
},
|
||||
unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct IncoherentImpl {
|
||||
pub file_id: hir_expand::HirFileId,
|
||||
pub impl_: syntax::AstPtr<syntax::ast::Impl>,
|
||||
}
|
||||
|
|
|
@ -275,7 +275,23 @@ impl<'a> InferenceContext<'a> {
|
|||
Some(type_ref) => self.make_ty(type_ref),
|
||||
None => self.table.new_type_var(),
|
||||
};
|
||||
sig_tys.push(ret_ty.clone());
|
||||
if let ClosureKind::Async = closure_kind {
|
||||
// Use the first type parameter as the output type of future.
|
||||
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
|
||||
let impl_trait_id =
|
||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
|
||||
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
||||
sig_tys.push(
|
||||
TyKind::OpaqueType(
|
||||
opaque_ty_id,
|
||||
Substitution::from1(Interner, ret_ty.clone()),
|
||||
)
|
||||
.intern(Interner),
|
||||
);
|
||||
} else {
|
||||
sig_tys.push(ret_ty.clone());
|
||||
}
|
||||
|
||||
let sig_ty = TyKind::Function(FnPointer {
|
||||
num_binders: 0,
|
||||
sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
|
||||
|
@ -286,33 +302,38 @@ impl<'a> InferenceContext<'a> {
|
|||
})
|
||||
.intern(Interner);
|
||||
|
||||
let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
|
||||
// FIXME: report error when there are more than 1 parameter.
|
||||
let resume_ty = match sig_tys.first() {
|
||||
// When `sig_tys.len() == 1` the first type is the return type, not the
|
||||
// first parameter type.
|
||||
Some(ty) if sig_tys.len() > 1 => ty.clone(),
|
||||
_ => self.result.standard_types.unit.clone(),
|
||||
};
|
||||
let yield_ty = self.table.new_type_var();
|
||||
let (ty, resume_yield_tys) = match closure_kind {
|
||||
ClosureKind::Generator(_) => {
|
||||
// FIXME: report error when there are more than 1 parameter.
|
||||
let resume_ty = match sig_tys.first() {
|
||||
// When `sig_tys.len() == 1` the first type is the return type, not the
|
||||
// first parameter type.
|
||||
Some(ty) if sig_tys.len() > 1 => ty.clone(),
|
||||
_ => self.result.standard_types.unit.clone(),
|
||||
};
|
||||
let yield_ty = self.table.new_type_var();
|
||||
|
||||
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
|
||||
.push(resume_ty.clone())
|
||||
.push(yield_ty.clone())
|
||||
.push(ret_ty.clone())
|
||||
.build();
|
||||
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
|
||||
.push(resume_ty.clone())
|
||||
.push(yield_ty.clone())
|
||||
.push(ret_ty.clone())
|
||||
.build();
|
||||
|
||||
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
|
||||
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
|
||||
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
|
||||
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
|
||||
|
||||
(generator_ty, Some((resume_ty, yield_ty)))
|
||||
} else {
|
||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||
let closure_ty =
|
||||
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
||||
.intern(Interner);
|
||||
(generator_ty, Some((resume_ty, yield_ty)))
|
||||
}
|
||||
ClosureKind::Closure | ClosureKind::Async => {
|
||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||
let closure_ty = TyKind::Closure(
|
||||
closure_id,
|
||||
Substitution::from1(Interner, sig_ty.clone()),
|
||||
)
|
||||
.intern(Interner);
|
||||
|
||||
(closure_ty, None)
|
||||
(closure_ty, None)
|
||||
}
|
||||
};
|
||||
|
||||
// Eagerly try to relate the closure type with the expected
|
||||
|
@ -321,7 +342,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
|
||||
|
||||
// Now go through the argument patterns
|
||||
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
||||
for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) {
|
||||
self.infer_top_pat(*arg_pat, &arg_ty);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@ use std::iter::repeat_with;
|
|||
use chalk_ir::Mutability;
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
expr::{
|
||||
Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId,
|
||||
RecordFieldPat,
|
||||
},
|
||||
expr::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
|
||||
path::Path,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
|
@ -439,38 +436,8 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
|
|||
|
||||
pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
|
||||
let mut res = false;
|
||||
walk_pats(body, pat_id, &mut |pat| {
|
||||
body.walk_pats(pat_id, &mut |pat| {
|
||||
res |= matches!(pat, Pat::Bind { id, .. } if body.bindings[*id].mode == BindingAnnotation::Ref);
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
fn walk_pats(body: &Body, pat_id: PatId, f: &mut impl FnMut(&Pat)) {
|
||||
let pat = &body[pat_id];
|
||||
f(pat);
|
||||
match pat {
|
||||
Pat::Range { .. }
|
||||
| Pat::Lit(..)
|
||||
| Pat::Path(..)
|
||||
| Pat::ConstBlock(..)
|
||||
| Pat::Wild
|
||||
| Pat::Missing => {}
|
||||
&Pat::Bind { subpat, .. } => {
|
||||
if let Some(subpat) = subpat {
|
||||
walk_pats(body, subpat, f);
|
||||
}
|
||||
}
|
||||
Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
|
||||
args.iter().copied().for_each(|p| walk_pats(body, p, f));
|
||||
}
|
||||
Pat::Ref { pat, .. } => walk_pats(body, *pat, f),
|
||||
Pat::Slice { prefix, slice, suffix } => {
|
||||
let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
|
||||
total_iter.copied().for_each(|p| walk_pats(body, p, f));
|
||||
}
|
||||
Pat::Record { args, .. } => {
|
||||
args.iter().for_each(|RecordFieldPat { pat, .. }| walk_pats(body, *pat, f));
|
||||
}
|
||||
Pat::Box { inner } => walk_pats(body, *inner, f),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,13 @@ use stdx::never;
|
|||
use crate::{
|
||||
autoderef::{self, AutoderefKind},
|
||||
db::HirDatabase,
|
||||
from_foreign_def_id,
|
||||
from_chalk_trait_id, from_foreign_def_id,
|
||||
infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
|
||||
primitive::{FloatTy, IntTy, UintTy},
|
||||
static_lifetime, to_chalk_trait_id,
|
||||
utils::all_super_traits,
|
||||
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
|
||||
Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
|
||||
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment,
|
||||
Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
|
||||
};
|
||||
|
||||
/// This is used as a key for indexing impls.
|
||||
|
@ -266,11 +266,12 @@ impl TraitImpls {
|
|||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct InherentImpls {
|
||||
map: FxHashMap<TyFingerprint, Vec<ImplId>>,
|
||||
invalid_impls: Vec<ImplId>,
|
||||
}
|
||||
|
||||
impl InherentImpls {
|
||||
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
|
||||
let mut impls = Self { map: FxHashMap::default() };
|
||||
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
impls.collect_def_map(db, &crate_def_map);
|
||||
|
@ -283,7 +284,7 @@ impl InherentImpls {
|
|||
db: &dyn HirDatabase,
|
||||
block: BlockId,
|
||||
) -> Option<Arc<Self>> {
|
||||
let mut impls = Self { map: FxHashMap::default() };
|
||||
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
||||
if let Some(block_def_map) = db.block_def_map(block) {
|
||||
impls.collect_def_map(db, &block_def_map);
|
||||
impls.shrink_to_fit();
|
||||
|
@ -306,11 +307,17 @@ impl InherentImpls {
|
|||
}
|
||||
|
||||
let self_ty = db.impl_self_ty(impl_id);
|
||||
let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
|
||||
if let Some(fp) = fp {
|
||||
self.map.entry(fp).or_default().push(impl_id);
|
||||
let self_ty = self_ty.skip_binders();
|
||||
|
||||
match is_inherent_impl_coherent(db, def_map, &data, self_ty) {
|
||||
true => {
|
||||
// `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
|
||||
if let Some(fp) = TyFingerprint::for_inherent_impl(self_ty) {
|
||||
self.map.entry(fp).or_default().push(impl_id);
|
||||
}
|
||||
}
|
||||
false => self.invalid_impls.push(impl_id),
|
||||
}
|
||||
// `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
|
||||
}
|
||||
|
||||
// To better support custom derives, collect impls in all unnamed const items.
|
||||
|
@ -334,6 +341,10 @@ impl InherentImpls {
|
|||
pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
|
||||
self.map.values().flat_map(|v| v.iter().copied())
|
||||
}
|
||||
|
||||
pub fn invalid_impls(&self) -> &[ImplId] {
|
||||
&self.invalid_impls
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn incoherent_inherent_impl_crates(
|
||||
|
@ -775,6 +786,69 @@ fn find_matching_impl(
|
|||
}
|
||||
}
|
||||
|
||||
fn is_inherent_impl_coherent(
|
||||
db: &dyn HirDatabase,
|
||||
def_map: &DefMap,
|
||||
impl_data: &ImplData,
|
||||
self_ty: &Ty,
|
||||
) -> bool {
|
||||
let self_ty = self_ty.kind(Interner);
|
||||
let impl_allowed = match self_ty {
|
||||
TyKind::Tuple(_, _)
|
||||
| TyKind::FnDef(_, _)
|
||||
| TyKind::Array(_, _)
|
||||
| TyKind::Never
|
||||
| TyKind::Raw(_, _)
|
||||
| TyKind::Ref(_, _, _)
|
||||
| TyKind::Slice(_)
|
||||
| TyKind::Str
|
||||
| TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(),
|
||||
|
||||
&TyKind::Adt(AdtId(adt), _) => adt.module(db.upcast()).krate() == def_map.krate(),
|
||||
TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
|
||||
from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate() == def_map.krate()
|
||||
}),
|
||||
|
||||
_ => true,
|
||||
};
|
||||
impl_allowed || {
|
||||
let rustc_has_incoherent_inherent_impls = match self_ty {
|
||||
TyKind::Tuple(_, _)
|
||||
| TyKind::FnDef(_, _)
|
||||
| TyKind::Array(_, _)
|
||||
| TyKind::Never
|
||||
| TyKind::Raw(_, _)
|
||||
| TyKind::Ref(_, _, _)
|
||||
| TyKind::Slice(_)
|
||||
| TyKind::Str
|
||||
| TyKind::Scalar(_) => true,
|
||||
|
||||
&TyKind::Adt(AdtId(adt), _) => match adt {
|
||||
hir_def::AdtId::StructId(it) => {
|
||||
db.struct_data(it).rustc_has_incoherent_inherent_impls
|
||||
}
|
||||
hir_def::AdtId::UnionId(it) => {
|
||||
db.union_data(it).rustc_has_incoherent_inherent_impls
|
||||
}
|
||||
hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls,
|
||||
},
|
||||
TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {
|
||||
db.trait_data(from_chalk_trait_id(trait_ref.trait_id))
|
||||
.rustc_has_incoherent_inherent_impls
|
||||
}),
|
||||
|
||||
_ => false,
|
||||
};
|
||||
rustc_has_incoherent_inherent_impls
|
||||
&& !impl_data.items.is_empty()
|
||||
&& impl_data.items.iter().copied().all(|assoc| match assoc {
|
||||
AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
|
||||
AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
|
||||
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iterate_path_candidates(
|
||||
ty: &Canonical<Ty>,
|
||||
db: &dyn HirDatabase,
|
||||
|
|
|
@ -1113,7 +1113,7 @@ impl MirLowerCtx<'_> {
|
|||
if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
|
||||
binding_mode = mode;
|
||||
}
|
||||
self.push_storage_live(*id, current)?;
|
||||
self.push_storage_live(*id, current);
|
||||
self.push_assignment(
|
||||
current,
|
||||
target_place.into(),
|
||||
|
@ -1327,8 +1327,9 @@ impl MirLowerCtx<'_> {
|
|||
is_ty_uninhabited_from(&self.infer[expr_id], self.owner.module(self.db.upcast()), self.db)
|
||||
}
|
||||
|
||||
/// This function push `StorageLive` statements for each binding in the pattern.
|
||||
fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) -> Result<()> {
|
||||
/// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` in
|
||||
/// the appropriated places.
|
||||
fn push_storage_live(&mut self, b: BindingId, current: BasicBlockId) {
|
||||
// Current implementation is wrong. It adds no `StorageDead` at the end of scope, and before each break
|
||||
// and continue. It just add a `StorageDead` before the `StorageLive`, which is not wrong, but unneeeded in
|
||||
// the proper implementation. Due this limitation, implementing a borrow checker on top of this mir will falsely
|
||||
|
@ -1356,7 +1357,6 @@ impl MirLowerCtx<'_> {
|
|||
let l = self.result.binding_locals[b];
|
||||
self.push_statement(current, StatementKind::StorageDead(l).with_span(span));
|
||||
self.push_statement(current, StatementKind::StorageLive(l).with_span(span));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_lang_item(&self, item: LangItem) -> Result<LangItemTarget> {
|
||||
|
@ -1381,10 +1381,10 @@ impl MirLowerCtx<'_> {
|
|||
if let Some(expr_id) = initializer {
|
||||
let else_block;
|
||||
let Some((init_place, c)) =
|
||||
self.lower_expr_as_place(current, *expr_id, true)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
self.lower_expr_as_place(current, *expr_id, true)?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
current = c;
|
||||
(current, else_block) = self.pattern_match(
|
||||
current,
|
||||
|
@ -1407,6 +1407,10 @@ impl MirLowerCtx<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.body.walk_bindings_in_pat(*pat, |b| {
|
||||
self.push_storage_live(b, current);
|
||||
});
|
||||
}
|
||||
}
|
||||
hir_def::expr::Statement::Expr { expr, has_semi: _ } => {
|
||||
|
|
|
@ -9,7 +9,7 @@ use base_db::{
|
|||
salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
|
||||
};
|
||||
use hir_def::{db::DefDatabase, ModuleId};
|
||||
use hir_expand::db::AstDatabase;
|
||||
use hir_expand::db::ExpandDatabase;
|
||||
use stdx::hash::{NoHashHashMap, NoHashHashSet};
|
||||
use syntax::TextRange;
|
||||
use test_utils::extract_annotations;
|
||||
|
@ -17,7 +17,7 @@ use test_utils::extract_annotations;
|
|||
#[salsa::database(
|
||||
base_db::SourceDatabaseExtStorage,
|
||||
base_db::SourceDatabaseStorage,
|
||||
hir_expand::db::AstDatabaseStorage,
|
||||
hir_expand::db::ExpandDatabaseStorage,
|
||||
hir_def::db::InternDatabaseStorage,
|
||||
hir_def::db::DefDatabaseStorage,
|
||||
crate::db::HirDatabaseStorage
|
||||
|
@ -41,8 +41,8 @@ impl fmt::Debug for TestDB {
|
|||
}
|
||||
}
|
||||
|
||||
impl Upcast<dyn AstDatabase> for TestDB {
|
||||
fn upcast(&self) -> &(dyn AstDatabase + 'static) {
|
||||
impl Upcast<dyn ExpandDatabase> for TestDB {
|
||||
fn upcast(&self) -> &(dyn ExpandDatabase + 'static) {
|
||||
&*self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ use hir_def::{
|
|||
src::HasSource,
|
||||
AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
|
||||
};
|
||||
use hir_expand::{db::AstDatabase, InFile};
|
||||
use hir_expand::{db::ExpandDatabase, InFile};
|
||||
use once_cell::race::OnceBool;
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
|
|
|
@ -9,6 +9,7 @@ fn infer_slice_method() {
|
|||
check_types(
|
||||
r#"
|
||||
impl<T> [T] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
fn foo(&self) -> T {
|
||||
loop {}
|
||||
}
|
||||
|
@ -35,6 +36,7 @@ fn test() {
|
|||
//- /lib.rs crate:other_crate
|
||||
mod foo {
|
||||
impl f32 {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn foo(self) -> f32 { 0. }
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +49,7 @@ fn infer_array_inherent_impl() {
|
|||
check_types(
|
||||
r#"
|
||||
impl<T, const N: usize> [T; N] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
fn foo(&self) -> T {
|
||||
loop {}
|
||||
}
|
||||
|
@ -1437,6 +1440,7 @@ fn resolve_const_generic_array_methods() {
|
|||
r#"
|
||||
#[lang = "array"]
|
||||
impl<T, const N: usize> [T; N] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn map<F, U>(self, f: F) -> [U; N]
|
||||
where
|
||||
F: FnMut(T) -> U,
|
||||
|
@ -1445,6 +1449,7 @@ impl<T, const N: usize> [T; N] {
|
|||
|
||||
#[lang = "slice"]
|
||||
impl<T> [T] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn map<F, U>(self, f: F) -> &[U]
|
||||
where
|
||||
F: FnMut(T) -> U,
|
||||
|
@ -1468,6 +1473,7 @@ struct Const<const N: usize>;
|
|||
|
||||
#[lang = "array"]
|
||||
impl<T, const N: usize> [T; N] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
|
||||
where
|
||||
F: FnMut(T) -> U,
|
||||
|
@ -1476,6 +1482,7 @@ impl<T, const N: usize> [T; N] {
|
|||
|
||||
#[lang = "slice"]
|
||||
impl<T> [T] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
|
||||
where
|
||||
F: FnMut(T) -> U,
|
||||
|
@ -1874,14 +1881,14 @@ fn incoherent_impls() {
|
|||
pub struct Box<T>(T);
|
||||
use core::error::Error;
|
||||
|
||||
#[rustc_allow_incoherent_impl]
|
||||
impl dyn Error {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
#[rustc_allow_incoherent_impl]
|
||||
impl dyn Error + Send {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
/// Attempts to downcast the box to a concrete type.
|
||||
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
|
||||
let err: Box<dyn Error> = self;
|
||||
|
|
|
@ -1756,3 +1756,35 @@ const C: usize = 2 + 2;
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_14164() {
|
||||
check_types(
|
||||
r#"
|
||||
trait Rec {
|
||||
type K;
|
||||
type Rebind<Tok>: Rec<K = Tok>;
|
||||
}
|
||||
|
||||
trait Expr<K> {
|
||||
type Part: Rec<K = K>;
|
||||
fn foo(_: <Self::Part as Rec>::Rebind<i32>) {}
|
||||
}
|
||||
|
||||
struct Head<K>(K);
|
||||
impl<K> Rec for Head<K> {
|
||||
type K = K;
|
||||
type Rebind<Tok> = Head<Tok>;
|
||||
}
|
||||
|
||||
fn test<E>()
|
||||
where
|
||||
E: Expr<usize, Part = Head<usize>>,
|
||||
{
|
||||
let head;
|
||||
//^^^^ Head<i32>
|
||||
E::foo(head);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1116,21 +1116,22 @@ fn infer_inherent_method() {
|
|||
fn infer_inherent_method_str() {
|
||||
check_infer(
|
||||
r#"
|
||||
#[lang = "str"]
|
||||
impl str {
|
||||
fn foo(&self) -> i32 {}
|
||||
}
|
||||
#![rustc_coherence_is_core]
|
||||
#[lang = "str"]
|
||||
impl str {
|
||||
fn foo(&self) -> i32 {}
|
||||
}
|
||||
|
||||
fn test() {
|
||||
"foo".foo();
|
||||
}
|
||||
"#,
|
||||
fn test() {
|
||||
"foo".foo();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
39..43 'self': &str
|
||||
52..54 '{}': i32
|
||||
68..88 '{ ...o(); }': ()
|
||||
74..79 '"foo"': &str
|
||||
74..85 '"foo".foo()': i32
|
||||
67..71 'self': &str
|
||||
80..82 '{}': i32
|
||||
96..116 '{ ...o(); }': ()
|
||||
102..107 '"foo"': &str
|
||||
102..113 '"foo".foo()': i32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -2640,6 +2641,7 @@ impl<T> [T] {}
|
|||
|
||||
#[lang = "slice_alloc"]
|
||||
impl<T> [T] {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -2655,22 +2657,22 @@ struct Astruct;
|
|||
impl B for Astruct {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
569..573 'self': Box<[T], A>
|
||||
602..634 '{ ... }': Vec<T, A>
|
||||
648..761 '{ ...t]); }': ()
|
||||
658..661 'vec': Vec<i32, Global>
|
||||
664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
|
||||
664..691 '<[_]>:...1i32])': Vec<i32, Global>
|
||||
680..690 'box [1i32]': Box<[i32; 1], Global>
|
||||
684..690 '[1i32]': [i32; 1]
|
||||
685..689 '1i32': i32
|
||||
701..702 'v': Vec<Box<dyn B, Global>, Global>
|
||||
722..739 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
|
||||
722..758 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
|
||||
740..757 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
|
||||
744..757 '[box Astruct]': [Box<dyn B, Global>; 1]
|
||||
745..756 'box Astruct': Box<Astruct, Global>
|
||||
749..756 'Astruct': Astruct
|
||||
604..608 'self': Box<[T], A>
|
||||
637..669 '{ ... }': Vec<T, A>
|
||||
683..796 '{ ...t]); }': ()
|
||||
693..696 'vec': Vec<i32, Global>
|
||||
699..714 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
|
||||
699..726 '<[_]>:...1i32])': Vec<i32, Global>
|
||||
715..725 'box [1i32]': Box<[i32; 1], Global>
|
||||
719..725 '[1i32]': [i32; 1]
|
||||
720..724 '1i32': i32
|
||||
736..737 'v': Vec<Box<dyn B, Global>, Global>
|
||||
757..774 '<[_]> ...to_vec': fn into_vec<Box<dyn B, Global>, Global>(Box<[Box<dyn B, Global>], Global>) -> Vec<Box<dyn B, Global>, Global>
|
||||
757..793 '<[_]> ...ruct])': Vec<Box<dyn B, Global>, Global>
|
||||
775..792 'box [b...truct]': Box<[Box<dyn B, Global>; 1], Global>
|
||||
779..792 '[box Astruct]': [Box<dyn B, Global>; 1]
|
||||
780..791 'box Astruct': Box<Astruct, Global>
|
||||
784..791 'Astruct': Astruct
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -82,6 +82,46 @@ async fn test() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_async_closure() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: future, option
|
||||
async fn test() {
|
||||
let f = async move |x: i32| x + 42;
|
||||
f;
|
||||
// ^ |i32| -> impl Future<Output = i32>
|
||||
let a = f(4);
|
||||
a;
|
||||
// ^ impl Future<Output = i32>
|
||||
let x = a.await;
|
||||
x;
|
||||
// ^ i32
|
||||
let f = async move || 42;
|
||||
f;
|
||||
// ^ || -> impl Future<Output = i32>
|
||||
let a = f();
|
||||
a;
|
||||
// ^ impl Future<Output = i32>
|
||||
let x = a.await;
|
||||
x;
|
||||
// ^ i32
|
||||
let b = ((async move || {})()).await;
|
||||
b;
|
||||
// ^ ()
|
||||
let c = async move || {
|
||||
let y = None;
|
||||
y
|
||||
// ^ Option<u64>
|
||||
};
|
||||
let _: Option<u64> = c().await;
|
||||
c;
|
||||
// ^ || -> impl Future<Output = Option<u64>>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_sized_async_block() {
|
||||
check_no_mismatches(
|
||||
|
@ -493,29 +533,30 @@ fn tuple_struct_with_fn() {
|
|||
r#"
|
||||
struct S(fn(u32) -> u64);
|
||||
fn test() -> u64 {
|
||||
let a = S(|i| 2*i);
|
||||
let a = S(|i| 2*i as u64);
|
||||
let b = a.0(4);
|
||||
a.0(2)
|
||||
}"#,
|
||||
expect![[r#"
|
||||
43..101 '{ ...0(2) }': u64
|
||||
43..108 '{ ...0(2) }': u64
|
||||
53..54 'a': S
|
||||
57..58 'S': S(fn(u32) -> u64) -> S
|
||||
57..67 'S(|i| 2*i)': S
|
||||
59..66 '|i| 2*i': |u32| -> u64
|
||||
57..74 'S(|i| ...s u64)': S
|
||||
59..73 '|i| 2*i as u64': |u32| -> u64
|
||||
60..61 'i': u32
|
||||
63..64 '2': u32
|
||||
63..66 '2*i': u32
|
||||
63..64 '2': u64
|
||||
63..73 '2*i as u64': u64
|
||||
65..66 'i': u32
|
||||
77..78 'b': u64
|
||||
81..82 'a': S
|
||||
81..84 'a.0': fn(u32) -> u64
|
||||
81..87 'a.0(4)': u64
|
||||
85..86 '4': u32
|
||||
93..94 'a': S
|
||||
93..96 'a.0': fn(u32) -> u64
|
||||
93..99 'a.0(2)': u64
|
||||
97..98 '2': u32
|
||||
65..73 'i as u64': u64
|
||||
84..85 'b': u64
|
||||
88..89 'a': S
|
||||
88..91 'a.0': fn(u32) -> u64
|
||||
88..94 'a.0(4)': u64
|
||||
92..93 '4': u32
|
||||
100..101 'a': S
|
||||
100..103 'a.0': fn(u32) -> u64
|
||||
100..106 'a.0(2)': u64
|
||||
104..105 '2': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue