Skip to content

Commit c93b070

Browse files
committed
⬆️ rust-analyzer
2 parents 7098c18 + 2e9f120 commit c93b070

File tree

25 files changed

+529
-143
lines changed

25 files changed

+529
-143
lines changed

src/tools/rust-analyzer/.github/workflows/release.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
- os: ubuntu-20.04
3535
target: x86_64-unknown-linux-gnu
3636
code-target: linux-x64
37+
container: ubuntu:18.04
3738
- os: ubuntu-20.04
3839
target: aarch64-unknown-linux-gnu
3940
code-target: linux-arm64
@@ -49,6 +50,7 @@ jobs:
4950

5051
name: dist (${{ matrix.target }})
5152
runs-on: ${{ matrix.os }}
53+
container: ${{ matrix.container }}
5254

5355
env:
5456
RA_TARGET: ${{ matrix.target }}
@@ -59,6 +61,14 @@ jobs:
5961
with:
6062
fetch-depth: ${{ env.FETCH_DEPTH }}
6163

64+
- name: Install toolchain dependencies
65+
if: matrix.container == 'ubuntu:18.04'
66+
shell: bash
67+
run: |
68+
apt-get update && apt-get install -y build-essential curl
69+
curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
70+
echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
71+
6272
- name: Install Rust toolchain
6373
run: |
6474
rustup update --no-self-update stable

src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs

+2
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ impl TyExt for Ty {
164164

165165
fn dyn_trait(&self) -> Option<TraitId> {
166166
let trait_ref = match self.kind(Interner) {
167+
// The principal trait bound should be the first element of the bounds. This is an
168+
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
167169
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
168170
match b.skip_binders() {
169171
WhereClause::Implemented(trait_ref) => Some(trait_ref),

src/tools/rust-analyzer/crates/hir-ty/src/lower.rs

+52-23
Original file line numberDiff line numberDiff line change
@@ -981,43 +981,72 @@ impl<'a> TyLoweringContext<'a> {
981981

982982
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
983983
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
984+
// INVARIANT: The principal trait bound must come first. Others may be in any order but
985+
// should be in the same order for the same set but possibly different order of bounds in
986+
// the input.
987+
// This invariant is used by `TyExt::dyn_trait()` and chalk.
984988
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
985-
let bounds =
986-
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
987-
988-
let mut auto_traits = SmallVec::<[_; 8]>::new();
989-
let mut regular_traits = SmallVec::<[_; 2]>::new();
990-
let mut other_bounds = SmallVec::<[_; 8]>::new();
991-
for bound in bounds {
992-
if let Some(id) = bound.trait_id() {
993-
if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
994-
auto_traits.push(bound);
995-
} else {
996-
regular_traits.push(bound);
989+
let mut bounds: Vec<_> = bounds
990+
.iter()
991+
.flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false))
992+
.collect();
993+
994+
let mut multiple_regular_traits = false;
995+
let mut multiple_same_projection = false;
996+
bounds.sort_unstable_by(|lhs, rhs| {
997+
use std::cmp::Ordering;
998+
match (lhs.skip_binders(), rhs.skip_binders()) {
999+
(WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
1000+
let lhs_id = lhs.trait_id;
1001+
let lhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(lhs_id)).is_auto;
1002+
let rhs_id = rhs.trait_id;
1003+
let rhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(rhs_id)).is_auto;
1004+
1005+
if !lhs_is_auto && !rhs_is_auto {
1006+
multiple_regular_traits = true;
1007+
}
1008+
// Note that the ordering here is important; this ensures the invariant
1009+
// mentioned above.
1010+
(lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id))
9971011
}
998-
} else {
999-
other_bounds.push(bound);
1012+
(WhereClause::Implemented(_), _) => Ordering::Less,
1013+
(_, WhereClause::Implemented(_)) => Ordering::Greater,
1014+
(WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => {
1015+
match (&lhs.alias, &rhs.alias) {
1016+
(AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => {
1017+
// We only compare the `associated_ty_id`s. We shouldn't have
1018+
// multiple bounds for an associated type in the correct Rust code,
1019+
// and if we do, we error out.
1020+
if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id {
1021+
multiple_same_projection = true;
1022+
}
1023+
lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id)
1024+
}
1025+
// We don't produce `AliasTy::Opaque`s yet.
1026+
_ => unreachable!(),
1027+
}
1028+
}
1029+
// We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet.
1030+
_ => unreachable!(),
10001031
}
1001-
}
1032+
});
10021033

1003-
if regular_traits.len() > 1 {
1034+
if multiple_regular_traits || multiple_same_projection {
10041035
return None;
10051036
}
10061037

1007-
auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
1008-
auto_traits.dedup();
1038+
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
1039+
// bounds. We shouldn't have repeated elements besides auto traits at this point.
1040+
bounds.dedup();
10091041

1010-
Some(QuantifiedWhereClauses::from_iter(
1011-
Interner,
1012-
regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
1013-
))
1042+
Some(QuantifiedWhereClauses::from_iter(Interner, bounds))
10141043
});
10151044

10161045
if let Some(bounds) = bounds {
10171046
let bounds = crate::make_single_type_binders(bounds);
10181047
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
10191048
} else {
1020-
// FIXME: report error (additional non-auto traits)
1049+
// FIXME: report error (additional non-auto traits or associated type rebound)
10211050
TyKind::Error.intern(Interner)
10221051
}
10231052
}

src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs

+28
Original file line numberDiff line numberDiff line change
@@ -3900,6 +3900,34 @@ fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
39003900
);
39013901
}
39023902

3903+
#[test]
3904+
fn dyn_multiple_projection_bounds() {
3905+
check_no_mismatches(
3906+
r#"
3907+
trait Trait {
3908+
type T;
3909+
type U;
3910+
}
3911+
3912+
fn f(t: &dyn Trait<T = (), U = ()>) {}
3913+
fn g(t: &dyn Trait<U = (), T = ()>) {
3914+
f(t);
3915+
}
3916+
"#,
3917+
);
3918+
3919+
check_types(
3920+
r#"
3921+
trait Trait {
3922+
type T;
3923+
}
3924+
3925+
fn f(t: &dyn Trait<T = (), T = ()>) {}
3926+
//^&{unknown}
3927+
"#,
3928+
);
3929+
}
3930+
39033931
#[test]
39043932
fn dyn_duplicate_auto_trait() {
39053933
check_no_mismatches(

src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
55
use ide_db::RootDatabase;
66
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
77
use itertools::Itertools;
8+
use syntax::ast::edit_in_place::Removable;
89
use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
910

1011
use crate::{

src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs

+20-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use ide_db::{
77
imports::insert_use::remove_path_if_in_use_stmt,
88
path_transform::PathTransform,
99
search::{FileReference, SearchScope},
10+
source_change::SourceChangeBuilder,
1011
syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
1112
RootDatabase,
1213
};
@@ -100,18 +101,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
100101
builder.edit_file(file_id);
101102
let count = refs.len();
102103
// The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️
103-
let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs
104-
.into_iter()
105-
.filter_map(|file_ref| match file_ref.name {
106-
ast::NameLike::NameRef(name_ref) => Some(name_ref),
107-
_ => None,
108-
})
109-
.partition_map(|name_ref| {
110-
match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
111-
Some(use_tree) => Either::Right(builder.make_mut(use_tree)),
112-
None => Either::Left(name_ref),
113-
}
114-
});
104+
let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some);
115105
let call_infos: Vec<_> = name_refs
116106
.into_iter()
117107
.filter_map(CallInfo::from_name_ref)
@@ -130,11 +120,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
130120
.count();
131121
if replaced + name_refs_use.len() == count {
132122
// we replaced all usages in this file, so we can remove the imports
133-
name_refs_use.into_iter().for_each(|use_tree| {
134-
if let Some(path) = use_tree.path() {
135-
remove_path_if_in_use_stmt(&path);
136-
}
137-
})
123+
name_refs_use.iter().for_each(remove_path_if_in_use_stmt);
138124
} else {
139125
remove_def = false;
140126
}
@@ -153,6 +139,23 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
153139
)
154140
}
155141

142+
pub(super) fn split_refs_and_uses<T: ast::AstNode>(
143+
builder: &mut SourceChangeBuilder,
144+
iter: impl IntoIterator<Item = FileReference>,
145+
mut map_ref: impl FnMut(ast::NameRef) -> Option<T>,
146+
) -> (Vec<T>, Vec<ast::Path>) {
147+
iter.into_iter()
148+
.filter_map(|file_ref| match file_ref.name {
149+
ast::NameLike::NameRef(name_ref) => Some(name_ref),
150+
_ => None,
151+
})
152+
.filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
153+
Some(use_tree) => builder.make_mut(use_tree).path().map(Either::Right),
154+
None => map_ref(name_ref).map(Either::Left),
155+
})
156+
.partition_map(|either| either)
157+
}
158+
156159
// Assist: inline_call
157160
//
158161
// Inlines a function or method body creating a `let` statement per parameter unless the parameter

src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs

+34-15
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
// - Remove unused aliases if there are no longer any users, see inline_call.rs.
44

55
use hir::{HasSource, PathResolution};
6-
use ide_db::{defs::Definition, search::FileReference};
6+
use ide_db::{
7+
defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt,
8+
search::FileReference,
9+
};
710
use itertools::Itertools;
811
use std::collections::HashMap;
912
use syntax::{
@@ -16,6 +19,8 @@ use crate::{
1619
AssistId, AssistKind,
1720
};
1821

22+
use super::inline_call::split_refs_and_uses;
23+
1924
// Assist: inline_type_alias_uses
2025
//
2126
// Inline a type alias into all of its uses where possible.
@@ -31,7 +36,7 @@ use crate::{
3136
// ```
3237
// ->
3338
// ```
34-
// type A = i32;
39+
//
3540
// fn id(x: i32) -> i32 {
3641
// x
3742
// };
@@ -58,32 +63,41 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
5863
name.syntax().text_range(),
5964
|builder| {
6065
let usages = usages.all();
66+
let mut definition_deleted = false;
6167

6268
let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
6369
builder.edit_file(file_id);
6470

65-
let path_types: Vec<ast::PathType> = refs
66-
.into_iter()
67-
.filter_map(|file_ref| match file_ref.name {
68-
ast::NameLike::NameRef(path_type) => {
69-
path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
70-
}
71-
_ => None,
72-
})
73-
.collect();
71+
let (path_types, path_type_uses) =
72+
split_refs_and_uses(builder, refs, |path_type| {
73+
path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
74+
});
7475

76+
path_type_uses
77+
.iter()
78+
.flat_map(ast_to_remove_for_path_in_use_stmt)
79+
.for_each(|x| builder.delete(x.syntax().text_range()));
7580
for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
7681
let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
7782
let target = path_type.syntax().text_range();
7883
Some((target, replacement))
7984
}) {
8085
builder.replace(target, replacement);
8186
}
87+
88+
if file_id == ctx.file_id() {
89+
builder.delete(ast_alias.syntax().text_range());
90+
definition_deleted = true;
91+
}
8292
};
8393

8494
for (file_id, refs) in usages.into_iter() {
8595
inline_refs_for_file(file_id, refs);
8696
}
97+
if !definition_deleted {
98+
builder.edit_file(ctx.file_id());
99+
builder.delete(ast_alias.syntax().text_range());
100+
}
87101
},
88102
)
89103
}
@@ -929,7 +943,7 @@ fn foo() {
929943
}
930944
"#,
931945
r#"
932-
type A = u32;
946+
933947
934948
fn foo() {
935949
let _: u32 = 3;
@@ -960,13 +974,13 @@ fn foo() {
960974
r#"
961975
//- /lib.rs
962976
mod foo;
963-
type T<E> = Vec<E>;
977+
964978
fn f() -> Vec<&str> {
965979
vec!["hello"]
966980
}
967981
968982
//- /foo.rs
969-
use super::T;
983+
970984
fn foo() {
971985
let _: Vec<i8> = Vec::new();
972986
}
@@ -990,7 +1004,12 @@ fn foo() {
9901004
}
9911005
"#,
9921006
r#"
993-
use super::I;
1007+
//- /lib.rs
1008+
mod foo;
1009+
1010+
1011+
//- /foo.rs
1012+
9941013
fn foo() {
9951014
let _: i32 = 0;
9961015
}

src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use either::Either;
22
use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
3-
use syntax::{algo::neighbor, ast, match_ast, ted, AstNode, SyntaxElement, SyntaxNode};
3+
use syntax::{
4+
algo::neighbor,
5+
ast::{self, edit_in_place::Removable},
6+
match_ast, ted, AstNode, SyntaxElement, SyntaxNode,
7+
};
48

59
use crate::{
610
assist_context::{AssistContext, Assists},
@@ -76,7 +80,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
7680
.collect();
7781
for edit in edits_mut {
7882
match edit {
79-
Remove(it) => it.as_ref().either(ast::Use::remove, ast::UseTree::remove),
83+
Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
8084
Replace(old, new) => ted::replace(old, new),
8185
}
8286
}

src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_bounds.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use syntax::{
2-
ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds},
2+
ast::{
3+
self,
4+
edit_in_place::{GenericParamsOwnerEdit, Removable},
5+
make, AstNode, HasName, HasTypeBounds,
6+
},
37
match_ast,
48
};
59

0 commit comments

Comments
 (0)