aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorDmitry <[email protected]>2020-02-16 17:36:48 +0000
committerDmitry <[email protected]>2020-02-16 17:36:48 +0000
commit58e15d12e4211306273b0128cb4a80b552889543 (patch)
tree70e129b7cd76c55d5cb86f9b084db001f73a2003 /crates
parentb446384956243ce6bdcef2a869123a2605e597ed (diff)
parent742b3b5744fbca1a5587e2898cd5b74d55853a47 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_cli/Cargo.toml2
-rw-r--r--crates/ra_cli/src/analysis_bench.rs2
-rw-r--r--crates/ra_cli/src/analysis_stats.rs83
-rw-r--r--crates/ra_cli/src/main.rs22
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs6
-rw-r--r--crates/ra_hir_ty/src/display.rs373
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs2
-rw-r--r--crates/ra_hir_ty/src/lib.rs383
-rw-r--r--crates/ra_hir_ty/src/lower.rs40
-rw-r--r--crates/ra_hir_ty/src/marks.rs2
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs9
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs22
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs32
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs48
-rw-r--r--crates/ra_hir_ty/src/traits.rs3
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs4
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html1
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs1
-rw-r--r--crates/ra_ide_db/Cargo.toml1
-rw-r--r--crates/ra_lsp_server/src/main.rs7
-rw-r--r--crates/ra_prof/src/lib.rs7
-rw-r--r--crates/ra_project_model/src/lib.rs6
24 files changed, 644 insertions, 415 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index bcd408421..53d4876f6 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -6,8 +6,10 @@ authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
9itertools = "0.8.0"
9pico-args = "0.3.0" 10pico-args = "0.3.0"
10env_logger = { version = "0.7.1", default-features = false } 11env_logger = { version = "0.7.1", default-features = false }
12rand = { version = "0.7.0", features = ["small_rng"] }
11 13
12ra_syntax = { path = "../ra_syntax" } 14ra_syntax = { path = "../ra_syntax" }
13ra_ide = { path = "../ra_ide" } 15ra_ide = { path = "../ra_ide" }
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 5485a38ff..764df6b9e 100644
--- a/crates/ra_cli/src/analysis_bench.rs
+++ b/crates/ra_cli/src/analysis_bench.rs
@@ -20,6 +20,8 @@ pub(crate) enum Op {
20} 20}
21 21
22pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { 22pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
23 ra_prof::init();
24
23 let start = Instant::now(); 25 let start = Instant::now();
24 eprint!("loading: "); 26 eprint!("loading: ");
25 let (mut host, roots) = ra_batch::load_cargo(path)?; 27 let (mut host, roots) = ra_batch::load_cargo(path)?;
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 833235bff..6d2dd34c6 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -2,6 +2,9 @@
2 2
3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
4 4
5use itertools::Itertools;
6use rand::{seq::SliceRandom, thread_rng};
7
5use hir::{ 8use hir::{
6 db::{DefDatabase, HirDatabase}, 9 db::{DefDatabase, HirDatabase},
7 AssocItem, Crate, HasSource, HirDisplay, ModuleDef, 10 AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
@@ -19,6 +22,7 @@ pub fn run(
19 path: &Path, 22 path: &Path,
20 only: Option<&str>, 23 only: Option<&str>,
21 with_deps: bool, 24 with_deps: bool,
25 randomize: bool,
22) -> Result<()> { 26) -> Result<()> {
23 let db_load_time = Instant::now(); 27 let db_load_time = Instant::now();
24 let (mut host, roots) = ra_batch::load_cargo(path)?; 28 let (mut host, roots) = ra_batch::load_cargo(path)?;
@@ -41,7 +45,11 @@ pub fn run(
41 }) 45 })
42 .collect::<HashSet<_>>(); 46 .collect::<HashSet<_>>();
43 47
44 for krate in Crate::all(db) { 48 let mut krates = Crate::all(db);
49 if randomize {
50 krates.shuffle(&mut thread_rng());
51 }
52 for krate in krates {
45 let module = krate.root_module(db).expect("crate without root module"); 53 let module = krate.root_module(db).expect("crate without root module");
46 let file_id = module.definition_source(db).file_id; 54 let file_id = module.definition_source(db).file_id;
47 if members.contains(&db.file_source_root(file_id.original_file(db))) { 55 if members.contains(&db.file_source_root(file_id.original_file(db))) {
@@ -50,6 +58,10 @@ pub fn run(
50 } 58 }
51 } 59 }
52 60
61 if randomize {
62 visit_queue.shuffle(&mut thread_rng());
63 }
64
53 println!("Crates in this dir: {}", num_crates); 65 println!("Crates in this dir: {}", num_crates);
54 let mut num_decls = 0; 66 let mut num_decls = 0;
55 let mut funcs = Vec::new(); 67 let mut funcs = Vec::new();
@@ -79,10 +91,14 @@ pub fn run(
79 println!("Total functions: {}", funcs.len()); 91 println!("Total functions: {}", funcs.len());
80 println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); 92 println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());
81 93
94 if randomize {
95 funcs.shuffle(&mut thread_rng());
96 }
97
82 let inference_time = Instant::now(); 98 let inference_time = Instant::now();
83 let mut bar = match verbosity { 99 let mut bar = match verbosity {
84 Verbosity::Verbose | Verbosity::Normal => ProgressReport::new(funcs.len() as u64), 100 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
85 Verbosity::Quiet => ProgressReport::hidden(), 101 _ => ProgressReport::new(funcs.len() as u64),
86 }; 102 };
87 103
88 bar.tick(); 104 bar.tick();
@@ -92,7 +108,20 @@ pub fn run(
92 let mut num_type_mismatches = 0; 108 let mut num_type_mismatches = 0;
93 for f in funcs { 109 for f in funcs {
94 let name = f.name(db); 110 let name = f.name(db);
95 let mut msg = format!("processing: {}", name); 111 let full_name = f
112 .module(db)
113 .path_to_root(db)
114 .into_iter()
115 .rev()
116 .filter_map(|it| it.name(db))
117 .chain(Some(f.name(db)))
118 .join("::");
119 if let Some(only_name) = only {
120 if name.to_string() != only_name && full_name != only_name {
121 continue;
122 }
123 }
124 let mut msg = format!("processing: {}", full_name);
96 if verbosity.is_verbose() { 125 if verbosity.is_verbose() {
97 let src = f.source(db); 126 let src = f.source(db);
98 let original_file = src.file_id.original_file(db); 127 let original_file = src.file_id.original_file(db);
@@ -100,15 +129,15 @@ pub fn run(
100 let syntax_range = src.value.syntax().text_range(); 129 let syntax_range = src.value.syntax().text_range();
101 write!(msg, " ({:?} {})", path, syntax_range).unwrap(); 130 write!(msg, " ({:?} {})", path, syntax_range).unwrap();
102 } 131 }
103 bar.set_message(&msg); 132 if verbosity.is_spammy() {
104 if let Some(only_name) = only { 133 bar.println(format!("{}", msg));
105 if name.to_string() != only_name {
106 continue;
107 }
108 } 134 }
135 bar.set_message(&msg);
109 let f_id = FunctionId::from(f); 136 let f_id = FunctionId::from(f);
110 let body = db.body(f_id.into()); 137 let body = db.body(f_id.into());
111 let inference_result = db.infer(f_id.into()); 138 let inference_result = db.infer(f_id.into());
139 let (previous_exprs, previous_unknown, previous_partially_unknown) =
140 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
112 for (expr_id, _) in body.exprs.iter() { 141 for (expr_id, _) in body.exprs.iter() {
113 let ty = &inference_result[expr_id]; 142 let ty = &inference_result[expr_id];
114 num_exprs += 1; 143 num_exprs += 1;
@@ -125,6 +154,33 @@ pub fn run(
125 num_exprs_partially_unknown += 1; 154 num_exprs_partially_unknown += 1;
126 } 155 }
127 } 156 }
157 if only.is_some() && verbosity.is_spammy() {
158 // in super-verbose mode for just one function, we print every single expression
159 let (_, sm) = db.body_with_source_map(f_id.into());
160 let src = sm.expr_syntax(expr_id);
161 if let Some(src) = src {
162 let original_file = src.file_id.original_file(db);
163 let line_index = host.analysis().file_line_index(original_file).unwrap();
164 let text_range = src.value.either(
165 |it| it.syntax_node_ptr().range(),
166 |it| it.syntax_node_ptr().range(),
167 );
168 let (start, end) = (
169 line_index.line_col(text_range.start()),
170 line_index.line_col(text_range.end()),
171 );
172 bar.println(format!(
173 "{}:{}-{}:{}: {}",
174 start.line + 1,
175 start.col_utf16,
176 end.line + 1,
177 end.col_utf16,
178 ty.display(db)
179 ));
180 } else {
181 bar.println(format!("unknown location: {}", ty.display(db)));
182 }
183 }
128 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 184 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
129 num_type_mismatches += 1; 185 num_type_mismatches += 1;
130 if verbosity.is_verbose() { 186 if verbosity.is_verbose() {
@@ -164,6 +220,15 @@ pub fn run(
164 } 220 }
165 } 221 }
166 } 222 }
223 if verbosity.is_spammy() {
224 bar.println(format!(
225 "In {}: {} exprs, {} unknown, {} partial",
226 full_name,
227 num_exprs - previous_exprs,
228 num_exprs_unknown - previous_unknown,
229 num_exprs_partially_unknown - previous_partially_unknown
230 ));
231 }
167 bar.inc(1); 232 bar.inc(1);
168 } 233 }
169 bar.finish_and_clear(); 234 bar.finish_and_clear();
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 806612c2c..6a0e447b9 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -16,6 +16,7 @@ type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
16 16
17#[derive(Clone, Copy)] 17#[derive(Clone, Copy)]
18pub enum Verbosity { 18pub enum Verbosity {
19 Spammy,
19 Verbose, 20 Verbose,
20 Normal, 21 Normal,
21 Quiet, 22 Quiet,
@@ -24,7 +25,13 @@ pub enum Verbosity {
24impl Verbosity { 25impl Verbosity {
25 fn is_verbose(self) -> bool { 26 fn is_verbose(self) -> bool {
26 match self { 27 match self {
27 Verbosity::Verbose => true, 28 Verbosity::Verbose | Verbosity::Spammy => true,
29 _ => false,
30 }
31 }
32 fn is_spammy(self) -> bool {
33 match self {
34 Verbosity::Spammy => true,
28 _ => false, 35 _ => false,
29 } 36 }
30 } 37 }
@@ -86,14 +93,18 @@ fn main() -> Result<()> {
86 return Ok(()); 93 return Ok(());
87 } 94 }
88 let verbosity = match ( 95 let verbosity = match (
96 matches.contains(["-vv", "--spammy"]),
89 matches.contains(["-v", "--verbose"]), 97 matches.contains(["-v", "--verbose"]),
90 matches.contains(["-q", "--quiet"]), 98 matches.contains(["-q", "--quiet"]),
91 ) { 99 ) {
92 (false, false) => Verbosity::Normal, 100 (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?,
93 (false, true) => Verbosity::Quiet, 101 (true, _, false) => Verbosity::Spammy,
94 (true, false) => Verbosity::Verbose, 102 (false, false, false) => Verbosity::Normal,
95 (true, true) => Err("Invalid flags: -q conflicts with -v")?, 103 (false, false, true) => Verbosity::Quiet,
104 (false, true, false) => Verbosity::Verbose,
105 (false, true, true) => Err("Invalid flags: -q conflicts with -v")?,
96 }; 106 };
107 let randomize = matches.contains("--randomize");
97 let memory_usage = matches.contains("--memory-usage"); 108 let memory_usage = matches.contains("--memory-usage");
98 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; 109 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
99 let with_deps: bool = matches.contains("--with-deps"); 110 let with_deps: bool = matches.contains("--with-deps");
@@ -111,6 +122,7 @@ fn main() -> Result<()> {
111 path.as_ref(), 122 path.as_ref(),
112 only.as_ref().map(String::as_ref), 123 only.as_ref().map(String::as_ref),
113 with_deps, 124 with_deps,
125 randomize,
114 )?; 126 )?;
115 } 127 }
116 "analysis-bench" => { 128 "analysis-bench" => {
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 6352c71ef..b1f3f525d 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -146,7 +146,7 @@ where
146 ReachedFixedPoint::Yes => break, 146 ReachedFixedPoint::Yes => break,
147 ReachedFixedPoint::No => i += 1, 147 ReachedFixedPoint::No => i += 1,
148 } 148 }
149 if i == 1000 { 149 if i == 10000 {
150 log::error!("name resolution is stuck"); 150 log::error!("name resolution is stuck");
151 break; 151 break;
152 } 152 }
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 05cf4646a..e2b228e80 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -542,11 +542,7 @@ impl Resolver {
542 542
543 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { 543 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
544 let params = db.generic_params(def); 544 let params = db.generic_params(def);
545 if params.types.is_empty() { 545 self.push_scope(Scope::GenericParams { def, params })
546 self
547 } else {
548 self.push_scope(Scope::GenericParams { def, params })
549 }
550 } 546 }
551 547
552 fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver { 548 fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver {
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index d1ff85f0f..14e089cf4 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -2,7 +2,12 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use crate::db::HirDatabase; 5use crate::{
6 db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
7 Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
8};
9use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup};
10use hir_expand::name::Name;
6 11
7pub struct HirFormatter<'a, 'b, DB> { 12pub struct HirFormatter<'a, 'b, DB> {
8 pub db: &'a DB, 13 pub db: &'a DB,
@@ -97,3 +102,369 @@ where
97 }) 102 })
98 } 103 }
99} 104}
105
106const TYPE_HINT_TRUNCATION: &str = "…";
107
108impl HirDisplay for &Ty {
109 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
110 HirDisplay::hir_fmt(*self, f)
111 }
112}
113
114impl HirDisplay for ApplicationTy {
115 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
116 if f.should_truncate() {
117 return write!(f, "{}", TYPE_HINT_TRUNCATION);
118 }
119
120 match self.ctor {
121 TypeCtor::Bool => write!(f, "bool")?,
122 TypeCtor::Char => write!(f, "char")?,
123 TypeCtor::Int(t) => write!(f, "{}", t)?,
124 TypeCtor::Float(t) => write!(f, "{}", t)?,
125 TypeCtor::Str => write!(f, "str")?,
126 TypeCtor::Slice => {
127 let t = self.parameters.as_single();
128 write!(f, "[{}]", t.display(f.db))?;
129 }
130 TypeCtor::Array => {
131 let t = self.parameters.as_single();
132 write!(f, "[{}; _]", t.display(f.db))?;
133 }
134 TypeCtor::RawPtr(m) => {
135 let t = self.parameters.as_single();
136 write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
137 }
138 TypeCtor::Ref(m) => {
139 let t = self.parameters.as_single();
140 let ty_display = if f.omit_verbose_types() {
141 t.display_truncated(f.db, f.max_size)
142 } else {
143 t.display(f.db)
144 };
145 write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?;
146 }
147 TypeCtor::Never => write!(f, "!")?,
148 TypeCtor::Tuple { .. } => {
149 let ts = &self.parameters;
150 if ts.len() == 1 {
151 write!(f, "({},)", ts[0].display(f.db))?;
152 } else {
153 write!(f, "(")?;
154 f.write_joined(&*ts.0, ", ")?;
155 write!(f, ")")?;
156 }
157 }
158 TypeCtor::FnPtr { .. } => {
159 let sig = FnSig::from_fn_ptr_substs(&self.parameters);
160 write!(f, "fn(")?;
161 f.write_joined(sig.params(), ", ")?;
162 write!(f, ") -> {}", sig.ret().display(f.db))?;
163 }
164 TypeCtor::FnDef(def) => {
165 let sig = f.db.callable_item_signature(def).subst(&self.parameters);
166 let name = match def {
167 CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(),
168 CallableDef::StructId(s) => f.db.struct_data(s).name.clone(),
169 CallableDef::EnumVariantId(e) => {
170 let enum_data = f.db.enum_data(e.parent);
171 enum_data.variants[e.local_id].name.clone()
172 }
173 };
174 match def {
175 CallableDef::FunctionId(_) => write!(f, "fn {}", name)?,
176 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
177 write!(f, "{}", name)?
178 }
179 }
180 if self.parameters.len() > 0 {
181 let generics = generics(f.db, def.into());
182 let (parent_params, self_param, type_params, _impl_trait_params) =
183 generics.provenance_split();
184 let total_len = parent_params + self_param + type_params;
185 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
186 if total_len > 0 {
187 write!(f, "<")?;
188 f.write_joined(&self.parameters.0[..total_len], ", ")?;
189 write!(f, ">")?;
190 }
191 }
192 write!(f, "(")?;
193 f.write_joined(sig.params(), ", ")?;
194 write!(f, ") -> {}", sig.ret().display(f.db))?;
195 }
196 TypeCtor::Adt(def_id) => {
197 let name = match def_id {
198 AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
199 AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
200 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
201 };
202 write!(f, "{}", name)?;
203 if self.parameters.len() > 0 {
204 write!(f, "<")?;
205
206 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
207 let parameters_to_write = if f.omit_verbose_types() {
208 match self
209 .ctor
210 .as_generic_def()
211 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
212 .filter(|defaults| !defaults.is_empty())
213 {
214 Option::None => self.parameters.0.as_ref(),
215 Option::Some(default_parameters) => {
216 for (i, parameter) in self.parameters.iter().enumerate() {
217 match (parameter, default_parameters.get(i)) {
218 (&Ty::Unknown, _) | (_, None) => {
219 non_default_parameters.push(parameter.clone())
220 }
221 (_, Some(default_parameter))
222 if parameter != default_parameter =>
223 {
224 non_default_parameters.push(parameter.clone())
225 }
226 _ => (),
227 }
228 }
229 &non_default_parameters
230 }
231 }
232 } else {
233 self.parameters.0.as_ref()
234 };
235
236 f.write_joined(parameters_to_write, ", ")?;
237 write!(f, ">")?;
238 }
239 }
240 TypeCtor::AssociatedType(type_alias) => {
241 let trait_ = match type_alias.lookup(f.db).container {
242 AssocContainerId::TraitId(it) => it,
243 _ => panic!("not an associated type"),
244 };
245 let trait_name = f.db.trait_data(trait_).name.clone();
246 let name = f.db.type_alias_data(type_alias).name.clone();
247 write!(f, "{}::{}", trait_name, name)?;
248 if self.parameters.len() > 0 {
249 write!(f, "<")?;
250 f.write_joined(&*self.parameters.0, ", ")?;
251 write!(f, ">")?;
252 }
253 }
254 TypeCtor::Closure { .. } => {
255 let sig = self.parameters[0]
256 .callable_sig(f.db)
257 .expect("first closure parameter should contain signature");
258 let return_type_hint = sig.ret().display(f.db);
259 if sig.params().is_empty() {
260 write!(f, "|| -> {}", return_type_hint)?;
261 } else if f.omit_verbose_types() {
262 write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
263 } else {
264 write!(f, "|")?;
265 f.write_joined(sig.params(), ", ")?;
266 write!(f, "| -> {}", return_type_hint)?;
267 };
268 }
269 }
270 Ok(())
271 }
272}
273
274impl HirDisplay for ProjectionTy {
275 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
276 if f.should_truncate() {
277 return write!(f, "{}", TYPE_HINT_TRUNCATION);
278 }
279
280 let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone();
281 write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?;
282 if self.parameters.len() > 1 {
283 write!(f, "<")?;
284 f.write_joined(&self.parameters[1..], ", ")?;
285 write!(f, ">")?;
286 }
287 write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?;
288 Ok(())
289 }
290}
291
292impl HirDisplay for Ty {
293 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
294 if f.should_truncate() {
295 return write!(f, "{}", TYPE_HINT_TRUNCATION);
296 }
297
298 match self {
299 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
300 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?,
301 Ty::Placeholder(id) => {
302 let generics = generics(f.db, id.parent);
303 let param_data = &generics.params.types[id.local_id];
304 match param_data.provenance {
305 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
306 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
307 }
308 TypeParamProvenance::ArgumentImplTrait => {
309 write!(f, "impl ")?;
310 let bounds = f.db.generic_predicates_for_param(*id);
311 let substs = Substs::type_params_for_generics(&generics);
312 write_bounds_like_dyn_trait(
313 &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
314 f,
315 )?;
316 }
317 }
318 }
319 Ty::Bound(idx) => write!(f, "?{}", idx)?,
320 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
321 match self {
322 Ty::Dyn(_) => write!(f, "dyn ")?,
323 Ty::Opaque(_) => write!(f, "impl ")?,
324 _ => unreachable!(),
325 };
326 write_bounds_like_dyn_trait(&predicates, f)?;
327 }
328 Ty::Unknown => write!(f, "{{unknown}}")?,
329 Ty::Infer(..) => write!(f, "_")?,
330 }
331 Ok(())
332 }
333}
334
335fn write_bounds_like_dyn_trait(
336 predicates: &[GenericPredicate],
337 f: &mut HirFormatter<impl HirDatabase>,
338) -> fmt::Result {
339 // Note: This code is written to produce nice results (i.e.
340 // corresponding to surface Rust) for types that can occur in
341 // actual Rust. It will have weird results if the predicates
342 // aren't as expected (i.e. self types = $0, projection
343 // predicates for a certain trait come after the Implemented
344 // predicate for that trait).
345 let mut first = true;
346 let mut angle_open = false;
347 for p in predicates.iter() {
348 match p {
349 GenericPredicate::Implemented(trait_ref) => {
350 if angle_open {
351 write!(f, ">")?;
352 }
353 if !first {
354 write!(f, " + ")?;
355 }
356 // We assume that the self type is $0 (i.e. the
357 // existential) here, which is the only thing that's
358 // possible in actual Rust, and hence don't print it
359 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?;
360 if trait_ref.substs.len() > 1 {
361 write!(f, "<")?;
362 f.write_joined(&trait_ref.substs[1..], ", ")?;
363 // there might be assoc type bindings, so we leave the angle brackets open
364 angle_open = true;
365 }
366 }
367 GenericPredicate::Projection(projection_pred) => {
368 // in types in actual Rust, these will always come
369 // after the corresponding Implemented predicate
370 if angle_open {
371 write!(f, ", ")?;
372 } else {
373 write!(f, "<")?;
374 angle_open = true;
375 }
376 let name =
377 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone();
378 write!(f, "{} = ", name)?;
379 projection_pred.ty.hir_fmt(f)?;
380 }
381 GenericPredicate::Error => {
382 if angle_open {
383 // impl Trait<X, {error}>
384 write!(f, ", ")?;
385 } else if !first {
386 // impl Trait + {error}
387 write!(f, " + ")?;
388 }
389 p.hir_fmt(f)?;
390 }
391 }
392 first = false;
393 }
394 if angle_open {
395 write!(f, ">")?;
396 }
397 Ok(())
398}
399
400impl TraitRef {
401 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
402 if f.should_truncate() {
403 return write!(f, "{}", TYPE_HINT_TRUNCATION);
404 }
405
406 self.substs[0].hir_fmt(f)?;
407 if use_as {
408 write!(f, " as ")?;
409 } else {
410 write!(f, ": ")?;
411 }
412 write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?;
413 if self.substs.len() > 1 {
414 write!(f, "<")?;
415 f.write_joined(&self.substs[1..], ", ")?;
416 write!(f, ">")?;
417 }
418 Ok(())
419 }
420}
421
422impl HirDisplay for TraitRef {
423 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
424 self.hir_fmt_ext(f, false)
425 }
426}
427
428impl HirDisplay for &GenericPredicate {
429 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
430 HirDisplay::hir_fmt(*self, f)
431 }
432}
433
434impl HirDisplay for GenericPredicate {
435 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
436 if f.should_truncate() {
437 return write!(f, "{}", TYPE_HINT_TRUNCATION);
438 }
439
440 match self {
441 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
442 GenericPredicate::Projection(projection_pred) => {
443 write!(f, "<")?;
444 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
445 write!(
446 f,
447 ">::{} = {}",
448 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name,
449 projection_pred.ty.display(f.db)
450 )?;
451 }
452 GenericPredicate::Error => write!(f, "{{error}}")?,
453 }
454 Ok(())
455 }
456}
457
458impl HirDisplay for Obligation {
459 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
460 match self {
461 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)),
462 Obligation::Projection(proj) => write!(
463 f,
464 "Normalize({} => {})",
465 proj.projection_ty.display(f.db),
466 proj.ty.display(f.db)
467 ),
468 }
469 }
470}
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index fe05642ae..1dc842f40 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -249,6 +249,8 @@ impl InferenceTable {
249 match (ty1, ty2) { 249 match (ty1, ty2) {
250 (Ty::Unknown, _) | (_, Ty::Unknown) => true, 250 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
251 251
252 (Ty::Placeholder(p1), Ty::Placeholder(p2)) if *p1 == *p2 => true,
253
252 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) 254 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
253 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) 255 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
254 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) 256 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index c5fe18c85..571579cc4 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -41,13 +41,12 @@ mod marks;
41 41
42use std::ops::Deref; 42use std::ops::Deref;
43use std::sync::Arc; 43use std::sync::Arc;
44use std::{fmt, iter, mem}; 44use std::{iter, mem};
45 45
46use hir_def::{ 46use hir_def::{
47 expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId, 47 expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId,
48 DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, 48 HasModule, Lookup, TraitId, TypeAliasId, TypeParamId,
49}; 49};
50use hir_expand::name::Name;
51use ra_db::{impl_intern_key, salsa, CrateId}; 50use ra_db::{impl_intern_key, salsa, CrateId};
52 51
53use crate::{ 52use crate::{
@@ -55,7 +54,7 @@ use crate::{
55 primitive::{FloatTy, IntTy, Uncertain}, 54 primitive::{FloatTy, IntTy, Uncertain},
56 utils::{generics, make_mut_slice, Generics}, 55 utils::{generics, make_mut_slice, Generics},
57}; 56};
58use display::{HirDisplay, HirFormatter}; 57use display::HirDisplay;
59 58
60pub use autoderef::autoderef; 59pub use autoderef::autoderef;
61pub use infer::{do_infer_query, InferTy, InferenceResult}; 60pub use infer::{do_infer_query, InferTy, InferenceResult};
@@ -291,7 +290,7 @@ pub enum Ty {
291 /// {}` when we're type-checking the body of that function. In this 290 /// {}` when we're type-checking the body of that function. In this
292 /// situation, we know this stands for *some* type, but don't know the exact 291 /// situation, we know this stands for *some* type, but don't know the exact
293 /// type. 292 /// type.
294 Param(TypeParamId), 293 Placeholder(TypeParamId),
295 294
296 /// A bound type variable. This is used in various places: when representing 295 /// A bound type variable. This is used in various places: when representing
297 /// some polymorphic type like the type of function `fn f<T>`, the type 296 /// some polymorphic type like the type of function `fn f<T>`, the type
@@ -365,7 +364,7 @@ impl Substs {
365 364
366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 365 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
367 pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs { 366 pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs {
368 Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect()) 367 Substs(generic_params.iter().map(|(id, _)| Ty::Placeholder(id)).collect())
369 } 368 }
370 369
371 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 370 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
@@ -813,7 +812,7 @@ impl TypeWalk for Ty {
813 p.walk(f); 812 p.walk(f);
814 } 813 }
815 } 814 }
816 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 815 Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
817 } 816 }
818 f(self); 817 f(self);
819 } 818 }
@@ -831,374 +830,8 @@ impl TypeWalk for Ty {
831 p.walk_mut_binders(f, binders + 1); 830 p.walk_mut_binders(f, binders + 1);
832 } 831 }
833 } 832 }
834 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 833 Ty::Placeholder { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
835 } 834 }
836 f(self, binders); 835 f(self, binders);
837 } 836 }
838} 837}
839
840const TYPE_HINT_TRUNCATION: &str = "…";
841
842impl HirDisplay for &Ty {
843 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
844 HirDisplay::hir_fmt(*self, f)
845 }
846}
847
848impl HirDisplay for ApplicationTy {
849 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
850 if f.should_truncate() {
851 return write!(f, "{}", TYPE_HINT_TRUNCATION);
852 }
853
854 match self.ctor {
855 TypeCtor::Bool => write!(f, "bool")?,
856 TypeCtor::Char => write!(f, "char")?,
857 TypeCtor::Int(t) => write!(f, "{}", t)?,
858 TypeCtor::Float(t) => write!(f, "{}", t)?,
859 TypeCtor::Str => write!(f, "str")?,
860 TypeCtor::Slice => {
861 let t = self.parameters.as_single();
862 write!(f, "[{}]", t.display(f.db))?;
863 }
864 TypeCtor::Array => {
865 let t = self.parameters.as_single();
866 write!(f, "[{}; _]", t.display(f.db))?;
867 }
868 TypeCtor::RawPtr(m) => {
869 let t = self.parameters.as_single();
870 write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
871 }
872 TypeCtor::Ref(m) => {
873 let t = self.parameters.as_single();
874 let ty_display = if f.omit_verbose_types() {
875 t.display_truncated(f.db, f.max_size)
876 } else {
877 t.display(f.db)
878 };
879 write!(f, "&{}{}", m.as_keyword_for_ref(), ty_display)?;
880 }
881 TypeCtor::Never => write!(f, "!")?,
882 TypeCtor::Tuple { .. } => {
883 let ts = &self.parameters;
884 if ts.len() == 1 {
885 write!(f, "({},)", ts[0].display(f.db))?;
886 } else {
887 write!(f, "(")?;
888 f.write_joined(&*ts.0, ", ")?;
889 write!(f, ")")?;
890 }
891 }
892 TypeCtor::FnPtr { .. } => {
893 let sig = FnSig::from_fn_ptr_substs(&self.parameters);
894 write!(f, "fn(")?;
895 f.write_joined(sig.params(), ", ")?;
896 write!(f, ") -> {}", sig.ret().display(f.db))?;
897 }
898 TypeCtor::FnDef(def) => {
899 let sig = f.db.callable_item_signature(def).subst(&self.parameters);
900 let name = match def {
901 CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(),
902 CallableDef::StructId(s) => f.db.struct_data(s).name.clone(),
903 CallableDef::EnumVariantId(e) => {
904 let enum_data = f.db.enum_data(e.parent);
905 enum_data.variants[e.local_id].name.clone()
906 }
907 };
908 match def {
909 CallableDef::FunctionId(_) => write!(f, "fn {}", name)?,
910 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
911 write!(f, "{}", name)?
912 }
913 }
914 if self.parameters.len() > 0 {
915 let generics = generics(f.db, def.into());
916 let (parent_params, self_param, type_params, _impl_trait_params) =
917 generics.provenance_split();
918 let total_len = parent_params + self_param + type_params;
919 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
920 if total_len > 0 {
921 write!(f, "<")?;
922 f.write_joined(&self.parameters.0[..total_len], ", ")?;
923 write!(f, ">")?;
924 }
925 }
926 write!(f, "(")?;
927 f.write_joined(sig.params(), ", ")?;
928 write!(f, ") -> {}", sig.ret().display(f.db))?;
929 }
930 TypeCtor::Adt(def_id) => {
931 let name = match def_id {
932 AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
933 AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
934 AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
935 };
936 write!(f, "{}", name)?;
937 if self.parameters.len() > 0 {
938 write!(f, "<")?;
939
940 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
941 let parameters_to_write = if f.omit_verbose_types() {
942 match self
943 .ctor
944 .as_generic_def()
945 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
946 .filter(|defaults| !defaults.is_empty())
947 {
948 Option::None => self.parameters.0.as_ref(),
949 Option::Some(default_parameters) => {
950 for (i, parameter) in self.parameters.iter().enumerate() {
951 match (parameter, default_parameters.get(i)) {
952 (&Ty::Unknown, _) | (_, None) => {
953 non_default_parameters.push(parameter.clone())
954 }
955 (_, Some(default_parameter))
956 if parameter != default_parameter =>
957 {
958 non_default_parameters.push(parameter.clone())
959 }
960 _ => (),
961 }
962 }
963 &non_default_parameters
964 }
965 }
966 } else {
967 self.parameters.0.as_ref()
968 };
969
970 f.write_joined(parameters_to_write, ", ")?;
971 write!(f, ">")?;
972 }
973 }
974 TypeCtor::AssociatedType(type_alias) => {
975 let trait_ = match type_alias.lookup(f.db).container {
976 AssocContainerId::TraitId(it) => it,
977 _ => panic!("not an associated type"),
978 };
979 let trait_name = f.db.trait_data(trait_).name.clone();
980 let name = f.db.type_alias_data(type_alias).name.clone();
981 write!(f, "{}::{}", trait_name, name)?;
982 if self.parameters.len() > 0 {
983 write!(f, "<")?;
984 f.write_joined(&*self.parameters.0, ", ")?;
985 write!(f, ">")?;
986 }
987 }
988 TypeCtor::Closure { .. } => {
989 let sig = self.parameters[0]
990 .callable_sig(f.db)
991 .expect("first closure parameter should contain signature");
992 let return_type_hint = sig.ret().display(f.db);
993 if sig.params().is_empty() {
994 write!(f, "|| -> {}", return_type_hint)?;
995 } else if f.omit_verbose_types() {
996 write!(f, "|{}| -> {}", TYPE_HINT_TRUNCATION, return_type_hint)?;
997 } else {
998 write!(f, "|")?;
999 f.write_joined(sig.params(), ", ")?;
1000 write!(f, "| -> {}", return_type_hint)?;
1001 };
1002 }
1003 }
1004 Ok(())
1005 }
1006}
1007
1008impl HirDisplay for ProjectionTy {
1009 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1010 if f.should_truncate() {
1011 return write!(f, "{}", TYPE_HINT_TRUNCATION);
1012 }
1013
1014 let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone();
1015 write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?;
1016 if self.parameters.len() > 1 {
1017 write!(f, "<")?;
1018 f.write_joined(&self.parameters[1..], ", ")?;
1019 write!(f, ">")?;
1020 }
1021 write!(f, ">::{}", f.db.type_alias_data(self.associated_ty).name)?;
1022 Ok(())
1023 }
1024}
1025
1026impl HirDisplay for Ty {
1027 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1028 if f.should_truncate() {
1029 return write!(f, "{}", TYPE_HINT_TRUNCATION);
1030 }
1031
1032 match self {
1033 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
1034 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?,
1035 Ty::Param(id) => {
1036 let generics = generics(f.db, id.parent);
1037 let param_data = &generics.params.types[id.local_id];
1038 match param_data.provenance {
1039 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1040 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
1041 }
1042 TypeParamProvenance::ArgumentImplTrait => {
1043 write!(f, "impl ")?;
1044 let bounds = f.db.generic_predicates_for_param(*id);
1045 let substs = Substs::type_params_for_generics(&generics);
1046 write_bounds_like_dyn_trait(
1047 &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
1048 f,
1049 )?;
1050 }
1051 }
1052 }
1053 Ty::Bound(idx) => write!(f, "?{}", idx)?,
1054 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
1055 match self {
1056 Ty::Dyn(_) => write!(f, "dyn ")?,
1057 Ty::Opaque(_) => write!(f, "impl ")?,
1058 _ => unreachable!(),
1059 };
1060 write_bounds_like_dyn_trait(&predicates, f)?;
1061 }
1062 Ty::Unknown => write!(f, "{{unknown}}")?,
1063 Ty::Infer(..) => write!(f, "_")?,
1064 }
1065 Ok(())
1066 }
1067}
1068
1069fn write_bounds_like_dyn_trait(
1070 predicates: &[GenericPredicate],
1071 f: &mut HirFormatter<impl HirDatabase>,
1072) -> fmt::Result {
1073 // Note: This code is written to produce nice results (i.e.
1074 // corresponding to surface Rust) for types that can occur in
1075 // actual Rust. It will have weird results if the predicates
1076 // aren't as expected (i.e. self types = $0, projection
1077 // predicates for a certain trait come after the Implemented
1078 // predicate for that trait).
1079 let mut first = true;
1080 let mut angle_open = false;
1081 for p in predicates.iter() {
1082 match p {
1083 GenericPredicate::Implemented(trait_ref) => {
1084 if angle_open {
1085 write!(f, ">")?;
1086 }
1087 if !first {
1088 write!(f, " + ")?;
1089 }
1090 // We assume that the self type is $0 (i.e. the
1091 // existential) here, which is the only thing that's
1092 // possible in actual Rust, and hence don't print it
1093 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?;
1094 if trait_ref.substs.len() > 1 {
1095 write!(f, "<")?;
1096 f.write_joined(&trait_ref.substs[1..], ", ")?;
1097 // there might be assoc type bindings, so we leave the angle brackets open
1098 angle_open = true;
1099 }
1100 }
1101 GenericPredicate::Projection(projection_pred) => {
1102 // in types in actual Rust, these will always come
1103 // after the corresponding Implemented predicate
1104 if angle_open {
1105 write!(f, ", ")?;
1106 } else {
1107 write!(f, "<")?;
1108 angle_open = true;
1109 }
1110 let name =
1111 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone();
1112 write!(f, "{} = ", name)?;
1113 projection_pred.ty.hir_fmt(f)?;
1114 }
1115 GenericPredicate::Error => {
1116 if angle_open {
1117 // impl Trait<X, {error}>
1118 write!(f, ", ")?;
1119 } else if !first {
1120 // impl Trait + {error}
1121 write!(f, " + ")?;
1122 }
1123 p.hir_fmt(f)?;
1124 }
1125 }
1126 first = false;
1127 }
1128 if angle_open {
1129 write!(f, ">")?;
1130 }
1131 Ok(())
1132}
1133
1134impl TraitRef {
1135 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
1136 if f.should_truncate() {
1137 return write!(f, "{}", TYPE_HINT_TRUNCATION);
1138 }
1139
1140 self.substs[0].hir_fmt(f)?;
1141 if use_as {
1142 write!(f, " as ")?;
1143 } else {
1144 write!(f, ": ")?;
1145 }
1146 write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?;
1147 if self.substs.len() > 1 {
1148 write!(f, "<")?;
1149 f.write_joined(&self.substs[1..], ", ")?;
1150 write!(f, ">")?;
1151 }
1152 Ok(())
1153 }
1154}
1155
1156impl HirDisplay for TraitRef {
1157 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1158 self.hir_fmt_ext(f, false)
1159 }
1160}
1161
1162impl HirDisplay for &GenericPredicate {
1163 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1164 HirDisplay::hir_fmt(*self, f)
1165 }
1166}
1167
1168impl HirDisplay for GenericPredicate {
1169 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1170 if f.should_truncate() {
1171 return write!(f, "{}", TYPE_HINT_TRUNCATION);
1172 }
1173
1174 match self {
1175 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
1176 GenericPredicate::Projection(projection_pred) => {
1177 write!(f, "<")?;
1178 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
1179 write!(
1180 f,
1181 ">::{} = {}",
1182 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name,
1183 projection_pred.ty.display(f.db)
1184 )?;
1185 }
1186 GenericPredicate::Error => write!(f, "{{error}}")?,
1187 }
1188 Ok(())
1189 }
1190}
1191
1192impl HirDisplay for Obligation {
1193 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
1194 match self {
1195 Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)),
1196 Obligation::Projection(proj) => write!(
1197 f,
1198 "Normalize({} => {})",
1199 proj.projection_ty.display(f.db),
1200 proj.ty.display(f.db)
1201 ),
1202 }
1203 }
1204}
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index c68c5852b..6a2aded02 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -14,9 +14,9 @@ use hir_def::{
14 path::{GenericArg, Path, PathSegment, PathSegments}, 14 path::{GenericArg, Path, PathSegment, PathSegments},
15 resolver::{HasResolver, Resolver, TypeNs}, 15 resolver::{HasResolver, Resolver, TypeNs},
16 type_ref::{TypeBound, TypeRef}, 16 type_ref::{TypeBound, TypeRef},
17 AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, 17 AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
18 LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 18 ImplId, LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
19 VariantId, 19 UnionId, VariantId,
20}; 20};
21use ra_arena::map::ArenaMap; 21use ra_arena::map::ArenaMap;
22use ra_db::CrateId; 22use ra_db::CrateId;
@@ -152,7 +152,7 @@ impl Ty {
152 data.provenance == TypeParamProvenance::ArgumentImplTrait 152 data.provenance == TypeParamProvenance::ArgumentImplTrait
153 }) 153 })
154 .nth(idx as usize) 154 .nth(idx as usize)
155 .map_or(Ty::Unknown, |(id, _)| Ty::Param(id)); 155 .map_or(Ty::Unknown, |(id, _)| Ty::Placeholder(id));
156 param 156 param
157 } else { 157 } else {
158 Ty::Unknown 158 Ty::Unknown
@@ -270,7 +270,7 @@ impl Ty {
270 let generics = 270 let generics =
271 generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope")); 271 generics(ctx.db, ctx.resolver.generic_def().expect("generics in scope"));
272 match ctx.type_param_mode { 272 match ctx.type_param_mode {
273 TypeParamLoweringMode::Placeholder => Ty::Param(param_id), 273 TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
274 TypeParamLoweringMode::Variable => { 274 TypeParamLoweringMode::Variable => {
275 let idx = generics.param_idx(param_id).expect("matching generics"); 275 let idx = generics.param_idx(param_id).expect("matching generics");
276 Ty::Bound(idx) 276 Ty::Bound(idx)
@@ -339,7 +339,7 @@ impl Ty {
339 None => return Ty::Unknown, // this can't actually happen 339 None => return Ty::Unknown, // this can't actually happen
340 }; 340 };
341 let param_id = match self_ty { 341 let param_id = match self_ty {
342 Ty::Param(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id, 342 Ty::Placeholder(id) if ctx.type_param_mode == TypeParamLoweringMode::Placeholder => id,
343 Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => { 343 Ty::Bound(idx) if ctx.type_param_mode == TypeParamLoweringMode::Variable => {
344 let generics = generics(ctx.db, def); 344 let generics = generics(ctx.db, def);
345 let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) { 345 let param_id = if let Some((id, _)) = generics.iter().nth(idx as usize) {
@@ -544,7 +544,7 @@ impl GenericPredicate {
544 let generics = generics(ctx.db, generic_def); 544 let generics = generics(ctx.db, generic_def);
545 let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id }; 545 let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
546 match ctx.type_param_mode { 546 match ctx.type_param_mode {
547 TypeParamLoweringMode::Placeholder => Ty::Param(param_id), 547 TypeParamLoweringMode::Placeholder => Ty::Placeholder(param_id),
548 TypeParamLoweringMode::Variable => { 548 TypeParamLoweringMode::Variable => {
549 let idx = generics.param_idx(param_id).expect("matching generics"); 549 let idx = generics.param_idx(param_id).expect("matching generics");
550 Ty::Bound(idx) 550 Ty::Bound(idx)
@@ -672,11 +672,35 @@ impl TraitEnvironment {
672 pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { 672 pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
673 let ctx = TyLoweringContext::new(db, &resolver) 673 let ctx = TyLoweringContext::new(db, &resolver)
674 .with_type_param_mode(TypeParamLoweringMode::Placeholder); 674 .with_type_param_mode(TypeParamLoweringMode::Placeholder);
675 let predicates = resolver 675 let mut predicates = resolver
676 .where_predicates_in_scope() 676 .where_predicates_in_scope()
677 .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) 677 .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred))
678 .collect::<Vec<_>>(); 678 .collect::<Vec<_>>();
679 679
680 if let Some(def) = resolver.generic_def() {
681 let container: Option<AssocContainerId> = match def {
682 // FIXME: is there a function for this?
683 GenericDefId::FunctionId(f) => Some(f.lookup(db).container),
684 GenericDefId::AdtId(_) => None,
685 GenericDefId::TraitId(_) => None,
686 GenericDefId::TypeAliasId(t) => Some(t.lookup(db).container),
687 GenericDefId::ImplId(_) => None,
688 GenericDefId::EnumVariantId(_) => None,
689 GenericDefId::ConstId(c) => Some(c.lookup(db).container),
690 };
691 if let Some(AssocContainerId::TraitId(trait_id)) = container {
692 // add `Self: Trait<T1, T2, ...>` to the environment in trait
693 // function default implementations (and hypothetical code
694 // inside consts or type aliases)
695 test_utils::tested_by!(trait_self_implements_self);
696 let substs = Substs::type_params(db, trait_id);
697 let trait_ref = TraitRef { trait_: trait_id, substs };
698 let pred = GenericPredicate::Implemented(trait_ref);
699
700 predicates.push(pred);
701 }
702 }
703
680 Arc::new(TraitEnvironment { predicates }) 704 Arc::new(TraitEnvironment { predicates })
681 } 705 }
682} 706}
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c..de5cb1d6b 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -4,6 +4,8 @@ test_utils::marks!(
4 type_var_cycles_resolve_completely 4 type_var_cycles_resolve_completely
5 type_var_cycles_resolve_as_possible 5 type_var_cycles_resolve_as_possible
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 impl_self_type_match_without_receiver
7 match_ergonomics_ref 8 match_ergonomics_ref
8 coerce_merge_fail_fallback 9 coerce_merge_fail_fallback
10 trait_self_implements_self
9); 11);
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 5283bff28..4f8c52433 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -425,6 +425,15 @@ fn iterate_inherent_methods<T>(
425 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { 425 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
426 continue; 426 continue;
427 } 427 }
428 // we have to check whether the self type unifies with the type
429 // that the impl is for. If we have a receiver type, this
430 // already happens in `is_valid_candidate` above; if not, we
431 // check it here
432 if receiver_ty.is_none() && inherent_impl_substs(db, impl_block, self_ty).is_none()
433 {
434 test_utils::tested_by!(impl_self_type_match_without_receiver);
435 continue;
436 }
428 if let Some(result) = callback(&self_ty.value, item) { 437 if let Some(result) = callback(&self_ty.value, item) {
429 return Some(result); 438 return Some(result);
430 } 439 }
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index fc5ef36a5..42330b269 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -526,3 +526,25 @@ fn test() {
526 "### 526 "###
527 ); 527 );
528} 528}
529
530#[test]
531fn coerce_placeholder_ref() {
532 // placeholders should unify, even behind references
533 assert_snapshot!(
534 infer_with_mismatches(r#"
535struct S<T> { t: T }
536impl<TT> S<TT> {
537 fn get(&self) -> &TT {
538 &self.t
539 }
540}
541"#, true),
542 @r###"
543 [51; 55) 'self': &S<TT>
544 [64; 87) '{ ... }': &TT
545 [74; 81) '&self.t': &TT
546 [75; 79) 'self': &S<TT>
547 [75; 81) 'self.t': TT
548 "###
549 );
550}
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 1722563aa..1f767d324 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -964,6 +964,38 @@ fn test() { S2.into()<|>; }
964} 964}
965 965
966#[test] 966#[test]
967fn method_resolution_overloaded_method() {
968 test_utils::covers!(impl_self_type_match_without_receiver);
969 let t = type_at(
970 r#"
971//- main.rs
972struct Wrapper<T>(T);
973struct Foo<T>(T);
974struct Bar<T>(T);
975
976impl<T> Wrapper<Foo<T>> {
977 pub fn new(foo_: T) -> Self {
978 Wrapper(Foo(foo_))
979 }
980}
981
982impl<T> Wrapper<Bar<T>> {
983 pub fn new(bar_: T) -> Self {
984 Wrapper(Bar(bar_))
985 }
986}
987
988fn main() {
989 let a = Wrapper::<Foo<f32>>::new(1.0);
990 let b = Wrapper::<Bar<f32>>::new(1.0);
991 (a, b)<|>;
992}
993"#,
994 );
995 assert_eq!(t, "(Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)")
996}
997
998#[test]
967fn method_resolution_encountering_fn_type() { 999fn method_resolution_encountering_fn_type() {
968 type_at( 1000 type_at(
969 r#" 1001 r#"
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 17611ddbf..aa2018944 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -300,6 +300,54 @@ fn test() {
300} 300}
301 301
302#[test] 302#[test]
303fn trait_default_method_self_bound_implements_trait() {
304 test_utils::covers!(trait_self_implements_self);
305 assert_snapshot!(
306 infer(r#"
307trait Trait {
308 fn foo(&self) -> i64;
309 fn bar(&self) -> {
310 let x = self.foo();
311 }
312}
313"#),
314 @r###"
315 [27; 31) 'self': &Self
316 [53; 57) 'self': &Self
317 [62; 97) '{ ... }': ()
318 [76; 77) 'x': i64
319 [80; 84) 'self': &Self
320 [80; 90) 'self.foo()': i64
321 "###
322 );
323}
324
325#[test]
326fn trait_default_method_self_bound_implements_super_trait() {
327 test_utils::covers!(trait_self_implements_self);
328 assert_snapshot!(
329 infer(r#"
330trait SuperTrait {
331 fn foo(&self) -> i64;
332}
333trait Trait: SuperTrait {
334 fn bar(&self) -> {
335 let x = self.foo();
336 }
337}
338"#),
339 @r###"
340 [32; 36) 'self': &Self
341 [86; 90) 'self': &Self
342 [95; 130) '{ ... }': ()
343 [109; 110) 'x': i64
344 [113; 117) 'self': &Self
345 [113; 123) 'self.foo()': i64
346 "###
347 );
348}
349
350#[test]
303fn infer_project_associated_type() { 351fn infer_project_associated_type() {
304 // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 352 // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
305 assert_snapshot!( 353 assert_snapshot!(
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 88af61e87..ff8e75b48 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -60,6 +60,9 @@ impl TraitSolver {
60 context.0.db.check_canceled(); 60 context.0.db.check_canceled();
61 let remaining = fuel.get(); 61 let remaining = fuel.get();
62 fuel.set(remaining - 1); 62 fuel.set(remaining - 1);
63 if remaining == 0 {
64 log::debug!("fuel exhausted");
65 }
63 remaining > 0 66 remaining > 0
64 }) 67 })
65 } 68 }
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 4974c565b..882160fa8 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -142,7 +142,7 @@ impl ToChalk for Ty {
142 let substitution = proj_ty.parameters.to_chalk(db); 142 let substitution = proj_ty.parameters.to_chalk(db);
143 chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() 143 chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern()
144 } 144 }
145 Ty::Param(id) => { 145 Ty::Placeholder(id) => {
146 let interned_id = db.intern_type_param_id(id); 146 let interned_id = db.intern_type_param_id(id);
147 PlaceholderIndex { 147 PlaceholderIndex {
148 ui: UniverseIndex::ROOT, 148 ui: UniverseIndex::ROOT,
@@ -184,7 +184,7 @@ impl ToChalk for Ty {
184 let interned_id = crate::db::GlobalTypeParamId::from_intern_id( 184 let interned_id = crate::db::GlobalTypeParamId::from_intern_id(
185 crate::salsa::InternId::from(idx.idx), 185 crate::salsa::InternId::from(idx.idx),
186 ); 186 );
187 Ty::Param(db.lookup_intern_type_param_id(interned_id)) 187 Ty::Placeholder(db.lookup_intern_type_param_id(interned_id))
188 } 188 }
189 chalk_ir::TyData::Alias(proj) => { 189 chalk_ir::TyData::Alias(proj) => {
190 let associated_ty = from_chalk(db, proj.associated_ty_id); 190 let associated_ty = from_chalk(db, proj.associated_ty_id);
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 1cc55e78b..a02dbaf2f 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
16.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; } 17.literal\.numeric { color: #6A8759; }
18.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
19.module { color: #AFD8AF; }
19.variable { color: #DCDCCC; } 20.variable { color: #DCDCCC; }
20.variable\.mut { color: #DCDCCC; text-decoration: underline; } 21.variable\.mut { color: #DCDCCC; text-decoration: underline; }
21 22
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 918fd4b97..95f038f00 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -16,6 +16,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
16.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; } 17.literal\.numeric { color: #6A8759; }
18.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
19.module { color: #AFD8AF; }
19.variable { color: #DCDCCC; } 20.variable { color: #DCDCCC; }
20.variable\.mut { color: #DCDCCC; text-decoration: underline; } 21.variable\.mut { color: #DCDCCC; text-decoration: underline; }
21 22
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 174e13595..20c414ca1 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -365,6 +365,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
365.literal { color: #BFEBBF; } 365.literal { color: #BFEBBF; }
366.literal\\.numeric { color: #6A8759; } 366.literal\\.numeric { color: #6A8759; }
367.macro { color: #94BFF3; } 367.macro { color: #94BFF3; }
368.module { color: #AFD8AF; }
368.variable { color: #DCDCCC; } 369.variable { color: #DCDCCC; }
369.variable\\.mut { color: #DCDCCC; text-decoration: underline; } 370.variable\\.mut { color: #DCDCCC; text-decoration: underline; }
370 371
diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml
index 716e88bc1..495fffb5a 100644
--- a/crates/ra_ide_db/Cargo.toml
+++ b/crates/ra_ide_db/Cargo.toml
@@ -22,7 +22,6 @@ fst = { version = "0.3.1", default-features = false }
22rustc-hash = "1.0" 22rustc-hash = "1.0"
23unicase = "2.2.0" 23unicase = "2.2.0"
24superslice = "1.0.0" 24superslice = "1.0.0"
25rand = { version = "0.7.0", features = ["small_rng"] }
26once_cell = "1.2.0" 25once_cell = "1.2.0"
27 26
28ra_syntax = { path = "../ra_syntax" } 27ra_syntax = { path = "../ra_syntax" }
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index c8a017c5c..ed2eaabd4 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -15,13 +15,8 @@ fn main() -> Result<()> {
15 15
16fn setup_logging() -> Result<()> { 16fn setup_logging() -> Result<()> {
17 std::env::set_var("RUST_BACKTRACE", "short"); 17 std::env::set_var("RUST_BACKTRACE", "short");
18
19 env_logger::try_init()?; 18 env_logger::try_init()?;
20 19 ra_prof::init();
21 ra_prof::set_filter(match std::env::var("RA_PROFILE") {
22 Ok(spec) => ra_prof::Filter::from_spec(&spec),
23 Err(_) => ra_prof::Filter::disabled(),
24 });
25 Ok(()) 20 Ok(())
26} 21}
27 22
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index d38ff397e..c0bfbc2ee 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -26,6 +26,13 @@ pub use crate::memory_usage::{Bytes, MemoryUsage};
26#[global_allocator] 26#[global_allocator]
27static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 27static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
28 28
29pub fn init() {
30 set_filter(match std::env::var("RA_PROFILE") {
31 Ok(spec) => Filter::from_spec(&spec),
32 Err(_) => Filter::disabled(),
33 });
34}
35
29/// Set profiling filter. It specifies descriptions allowed to profile. 36/// Set profiling filter. It specifies descriptions allowed to profile.
30/// This is helpful when call stack has too many nested profiling scopes. 37/// This is helpful when call stack has too many nested profiling scopes.
31/// Additionally filter can specify maximum depth of profiling scopes nesting. 38/// Additionally filter can specify maximum depth of profiling scopes nesting.
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index fef405b7f..250255813 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -418,8 +418,10 @@ pub fn get_rustc_cfg_options() -> CfgOptions {
418 // Some nightly-only cfgs, which are required for stdlib 418 // Some nightly-only cfgs, which are required for stdlib
419 { 419 {
420 cfg_options.insert_atom("target_thread_local".into()); 420 cfg_options.insert_atom("target_thread_local".into());
421 for &target_has_atomic in ["16", "32", "64", "8", "cas", "ptr"].iter() { 421 for &target_has_atomic in ["8", "16", "32", "64", "cas", "ptr"].iter() {
422 cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into()) 422 cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into());
423 cfg_options
424 .insert_key_value("target_has_atomic_load_store".into(), target_has_atomic.into());
423 } 425 }
424 } 426 }
425 427