Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
//! Loads "sysroot" crate.
//!
//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.

use std::{env, fs, iter, ops, path::PathBuf, process::Command, sync::Arc};

use anyhow::{format_err, Result};
use base_db::CrateName;
use itertools::Itertools;
use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;
use toolchain::{probe_for_binary, Tool};

use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};

#[derive(Debug, Clone)]
pub struct Sysroot {
    root: AbsPathBuf,
    src_root: Option<Result<AbsPathBuf, Arc<anyhow::Error>>>,
    mode: SysrootMode,
}

impl Eq for Sysroot {}
impl PartialEq for Sysroot {
    fn eq(&self, other: &Self) -> bool {
        self.root == other.root
            && self.mode == other.mode
            && match (&self.src_root, &other.src_root) {
                (Some(Ok(this)), Some(Ok(other))) => this == other,
                (None, None) | (Some(Err(_)), Some(Err(_))) => true,
                _ => false,
            }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum SysrootMode {
    Workspace(CargoWorkspace),
    Stitched(Stitched),
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct Stitched {
    crates: Arena<SysrootCrateData>,
}

impl ops::Index<SysrootCrate> for Stitched {
    type Output = SysrootCrateData;
    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
        &self.crates[index]
    }
}

impl Stitched {
    pub(crate) fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
        // core is added as a dependency before std in order to
        // mimic rustcs dependency order
        ["core", "alloc", "std"]
            .into_iter()
            .zip(iter::repeat(true))
            .chain(iter::once(("test", false)))
            .filter_map(move |(name, prelude)| {
                Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
            })
    }

    pub(crate) fn proc_macro(&self) -> Option<SysrootCrate> {
        self.by_name("proc_macro")
    }

    pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = SysrootCrate> + '_ {
        self.crates.iter().map(|(id, _data)| id)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
        Some(id)
    }
}

pub(crate) type SysrootCrate = Idx<SysrootCrateData>;

#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct SysrootCrateData {
    pub(crate) name: String,
    pub(crate) root: ManifestPath,
    pub(crate) deps: Vec<SysrootCrate>,
}

impl Sysroot {
    /// Returns sysroot "root" directory, where `bin/`, `etc/`, `lib/`, `libexec/`
    /// subfolder live, like:
    /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu`
    pub fn root(&self) -> &AbsPath {
        &self.root
    }

    /// Returns the sysroot "source" directory, where stdlib sources are located, like:
    /// `$HOME/.rustup/toolchains/nightly-2022-07-23-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library`
    pub fn src_root(&self) -> Option<&AbsPath> {
        self.src_root.as_ref()?.as_deref().ok()
    }

    pub fn is_empty(&self) -> bool {
        match &self.mode {
            SysrootMode::Workspace(ws) => ws.packages().next().is_none(),
            SysrootMode::Stitched(stitched) => stitched.crates.is_empty(),
        }
    }

    pub fn loading_warning(&self) -> Option<String> {
        let src_root = match &self.src_root {
            None => return Some(format!("sysroot at `{}` has no library sources", self.root)),
            Some(Ok(src_root)) => src_root,
            Some(Err(e)) => return Some(e.to_string()),
        };
        let has_core = match &self.mode {
            SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
            SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
        };
        if !has_core {
            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
            } else {
                " try running `rustup component add rust-src` to possible fix this"
            };
            Some(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
        } else {
            None
        }
    }

    pub fn num_packages(&self) -> usize {
        match &self.mode {
            SysrootMode::Workspace(ws) => ws.packages().count(),
            SysrootMode::Stitched(c) => c.crates().count(),
        }
    }

    pub(crate) fn mode(&self) -> &SysrootMode {
        &self.mode
    }
}

// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated.
impl Sysroot {
    /// Attempts to discover the toolchain's sysroot from the given `dir`.
    pub fn discover(
        dir: &AbsPath,
        extra_env: &FxHashMap<String, String>,
        metadata: bool,
    ) -> Result<Sysroot> {
        tracing::debug!("discovering sysroot for {dir}");
        let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
        let sysroot_src_dir =
            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env);
        Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata))
    }

    pub fn discover_no_source(
        dir: &AbsPath,
        extra_env: &FxHashMap<String, String>,
    ) -> Result<Sysroot> {
        tracing::debug!("discovering sysroot for {dir}");
        let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
        let sysroot_src_dir =
            discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env);
        Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), false))
    }

    pub fn discover_with_src_override(
        current_dir: &AbsPath,
        extra_env: &FxHashMap<String, String>,
        src: AbsPathBuf,
        metadata: bool,
    ) -> Result<Sysroot> {
        tracing::debug!("discovering sysroot for {current_dir}");
        let sysroot_dir = discover_sysroot_dir(current_dir, extra_env)?;
        Ok(Sysroot::load(sysroot_dir, Some(Ok(src)), metadata))
    }

    pub fn discover_rustc_src(&self) -> Option<ManifestPath> {
        get_rustc_src(&self.root)
    }

    pub fn with_sysroot_dir(sysroot_dir: AbsPathBuf, metadata: bool) -> Result<Sysroot> {
        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
            format_err!("can't load standard library from sysroot path {sysroot_dir}")
        });
        Ok(Sysroot::load(sysroot_dir, Some(sysroot_src_dir), metadata))
    }

    /// Returns a command to run a tool preferring the cargo proxies if the sysroot exists.
    pub fn tool(sysroot: Option<&Self>, tool: Tool) -> Command {
        match sysroot {
            Some(sysroot) => {
                // special case rustc, we can look that up directly in the sysroot's bin folder
                // as it should never invoke another cargo binary
                if let Tool::Rustc = tool {
                    if let Some(path) =
                        probe_for_binary(sysroot.root.join("bin").join(Tool::Rustc.name()).into())
                    {
                        return Command::new(path);
                    }
                }

                let mut cmd = Command::new(tool.prefer_proxy());
                cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(&sysroot.root));
                cmd
            }
            _ => Command::new(tool.path()),
        }
    }

    pub fn discover_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
        ["libexec", "lib"]
            .into_iter()
            .map(|segment| self.root().join(segment).join("rust-analyzer-proc-macro-srv"))
            .find_map(|server_path| probe_for_binary(server_path.into()))
            .map(AbsPathBuf::assert)
            .ok_or_else(|| {
                anyhow::format_err!("cannot find proc-macro server in sysroot `{}`", self.root())
            })
    }

    pub fn load(
        sysroot_dir: AbsPathBuf,
        sysroot_src_dir: Option<Result<AbsPathBuf, anyhow::Error>>,
        metadata: bool,
    ) -> Sysroot {
        let sysroot_src_dir = match sysroot_src_dir {
            Some(Ok(sysroot_src_dir)) => sysroot_src_dir,
            Some(Err(e)) => {
                return Sysroot {
                    root: sysroot_dir,
                    src_root: Some(Err(Arc::new(e))),
                    mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }),
                }
            }
            None => {
                return Sysroot {
                    root: sysroot_dir,
                    src_root: None,
                    mode: SysrootMode::Stitched(Stitched { crates: Arena::default() }),
                }
            }
        };
        if metadata {
            let sysroot: Option<_> = (|| {
                let sysroot_cargo_toml = ManifestPath::try_from(
                    AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot/Cargo.toml")).ok()?,
                )
                .ok()?;
                let current_dir =
                    AbsPathBuf::try_from(&*format!("{sysroot_src_dir}/sysroot")).ok()?;

                let mut cargo_config = CargoConfig::default();
                // the sysroot uses `public-dependency`, so we make cargo think it's a nightly
                cargo_config.extra_env.insert(
                    "__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(),
                    "nightly".to_owned(),
                );

                let res = CargoWorkspace::fetch_metadata(
                    &sysroot_cargo_toml,
                    &current_dir,
                    &cargo_config,
                    None,
                    &|_| (),
                )
                .map_err(|e| {
                    tracing::error!(
                        "failed to load sysroot `{sysroot_src_dir}/sysroot/Cargo.toml`: {}",
                        e
                    );
                    e
                });
                if let Err(e) =
                    std::fs::remove_file(format!("{sysroot_src_dir}/sysroot/Cargo.lock"))
                {
                    tracing::error!(
                        "failed to remove sysroot `{sysroot_src_dir}/sysroot/Cargo.lock`: {}",
                        e
                    )
                }
                let mut res = res.ok()?;

                // Patch out `rustc-std-workspace-*` crates to point to the real crates.
                // This is done prior to `CrateGraph` construction to avoid having duplicate `std` targets.

                let mut fake_core = None;
                let mut fake_alloc = None;
                let mut fake_std = None;
                let mut real_core = None;
                let mut real_alloc = None;
                let mut real_std = None;
                res.packages.iter().enumerate().for_each(|(idx, package)| {
                    match package.name.strip_prefix("rustc-std-workspace-") {
                        Some("core") => fake_core = Some((idx, package.id.clone())),
                        Some("alloc") => fake_alloc = Some((idx, package.id.clone())),
                        Some("std") => fake_std = Some((idx, package.id.clone())),
                        Some(_) => {
                            tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name)
                        }
                        None => match &*package.name {
                            "core" => real_core = Some(package.id.clone()),
                            "alloc" => real_alloc = Some(package.id.clone()),
                            "std" => real_std = Some(package.id.clone()),
                            _ => (),
                        },
                    }
                });

                let patches =
                    [fake_core.zip(real_core), fake_alloc.zip(real_alloc), fake_std.zip(real_std)]
                        .into_iter()
                        .flatten();

                let resolve = res.resolve.as_mut().expect("metadata executed with deps");
                let mut remove_nodes = vec![];
                for (idx, node) in resolve.nodes.iter_mut().enumerate() {
                    // Replace them in the dependency list
                    node.deps.iter_mut().for_each(|dep| {
                        if let Some((_, real)) =
                            patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg)
                        {
                            dep.pkg = real;
                        }
                    });
                    if patches.clone().any(|((_, fake), _)| fake == node.id) {
                        remove_nodes.push(idx);
                    }
                }
                // Remove the fake ones from the resolve data
                remove_nodes.into_iter().rev().for_each(|r| {
                    resolve.nodes.remove(r);
                });
                // Remove the fake ones from the packages
                patches.map(|((r, _), _)| r).sorted().rev().for_each(|r| {
                    res.packages.remove(r);
                });

                res.workspace_members = res
                    .packages
                    .iter()
                    .filter(|&package| RELEVANT_SYSROOT_CRATES.contains(&&*package.name))
                    .map(|package| package.id.clone())
                    .collect();
                let cargo_workspace = CargoWorkspace::new(res);
                Some(Sysroot {
                    root: sysroot_dir.clone(),
                    src_root: Some(Ok(sysroot_src_dir.clone())),
                    mode: SysrootMode::Workspace(cargo_workspace),
                })
            })();
            if let Some(sysroot) = sysroot {
                return sysroot;
            }
        }
        let mut stitched = Stitched { crates: Arena::default() };

        for path in SYSROOT_CRATES.trim().lines() {
            let name = path.split('/').last().unwrap();
            let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")]
                .into_iter()
                .map(|it| sysroot_src_dir.join(it))
                .filter_map(|it| ManifestPath::try_from(it).ok())
                .find(|it| fs::metadata(it).is_ok());

            if let Some(root) = root {
                stitched.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }

        if let Some(std) = stitched.by_name("std") {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = stitched.by_name(dep) {
                    stitched.crates[std].deps.push(dep)
                }
            }
        }

        if let Some(alloc) = stitched.by_name("alloc") {
            for dep in ALLOC_DEPS.trim().lines() {
                if let Some(dep) = stitched.by_name(dep) {
                    stitched.crates[alloc].deps.push(dep)
                }
            }
        }

        if let Some(proc_macro) = stitched.by_name("proc_macro") {
            for dep in PROC_MACRO_DEPS.trim().lines() {
                if let Some(dep) = stitched.by_name(dep) {
                    stitched.crates[proc_macro].deps.push(dep)
                }
            }
        }
        Sysroot {
            root: sysroot_dir,
            src_root: Some(Ok(sysroot_src_dir)),
            mode: SysrootMode::Stitched(stitched),
        }
    }
}

fn discover_sysroot_dir(
    current_dir: &AbsPath,
    extra_env: &FxHashMap<String, String>,
) -> Result<AbsPathBuf> {
    let mut rustc = Command::new(Tool::Rustc.path());
    rustc.envs(extra_env);
    rustc.current_dir(current_dir).args(["--print", "sysroot"]);
    tracing::debug!("Discovering sysroot by {:?}", rustc);
    let stdout = utf8_stdout(rustc)?;
    Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
}

fn discover_sysroot_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
    if let Ok(path) = env::var("RUST_SRC_PATH") {
        if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
            let core = path.join("core");
            if fs::metadata(&core).is_ok() {
                tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {path}");
                return Some(path);
            }
            tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {core:?}), ignoring");
        } else {
            tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
        }
    }

    get_rust_src(sysroot_path)
}

fn discover_sysroot_src_dir_or_add_component(
    sysroot_path: &AbsPathBuf,
    current_dir: &AbsPath,
    extra_env: &FxHashMap<String, String>,
) -> Result<AbsPathBuf> {
    discover_sysroot_src_dir(sysroot_path)
        .or_else(|| {
            let mut rustup = Command::new(Tool::Rustup.prefer_proxy());
            rustup.envs(extra_env);
            rustup.current_dir(current_dir).args(["component", "add", "rust-src"]);
            tracing::info!("adding rust-src component by {:?}", rustup);
            utf8_stdout(rustup).ok()?;
            get_rust_src(sysroot_path)
        })
        .ok_or_else(|| {
            format_err!(
                "\
can't load standard library from sysroot
{sysroot_path}
(discovered via `rustc --print sysroot`)
try installing the Rust source the same way you installed rustc",
            )
        })
}

fn get_rustc_src(sysroot_path: &AbsPath) -> Option<ManifestPath> {
    let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
    let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
    tracing::debug!("checking for rustc source code: {rustc_src}");
    if fs::metadata(&rustc_src).is_ok() {
        Some(rustc_src)
    } else {
        None
    }
}

fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
    let rust_src = sysroot_path.join("lib/rustlib/src/rust/library");
    tracing::debug!("checking sysroot library: {rust_src}");
    if fs::metadata(&rust_src).is_ok() {
        Some(rust_src)
    } else {
        None
    }
}

const SYSROOT_CRATES: &str = "
alloc
backtrace
core
panic_abort
panic_unwind
proc_macro
profiler_builtins
std
stdarch/crates/std_detect
test
unwind";

const ALLOC_DEPS: &str = "core";

const STD_DEPS: &str = "
alloc
panic_unwind
panic_abort
core
profiler_builtins
unwind
std_detect
test";

// core is required for our builtin derives to work in the proc_macro lib currently
const PROC_MACRO_DEPS: &str = "
std
core";

const RELEVANT_SYSROOT_CRATES: &[&str] = &["core", "alloc", "std", "test", "proc_macro"];
nd-color: #1f2430; color: #cccac2">//! This module is concerned with finding methods that a given type provides. //! For details about how this works in rustc, see the method lookup page in the //! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) //! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. use std::{iter, ops::ControlFlow, sync::Arc}; use arrayvec::ArrayVec; use base_db::{CrateId, Edition}; use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; use hir_def::{ item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId, }; use hir_expand::name::Name; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::never; use crate::{ autoderef::{self, AutoderefKind}, db::HirDatabase, from_foreign_def_id, infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast}, primitive::{FloatTy, IntTy, UintTy}, static_lifetime, utils::all_super_traits, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner, Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, }; /// This is used as a key for indexing impls. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum TyFingerprint { // These are lang item impls: Str, Slice, Array, Never, RawPtr(Mutability), Scalar(Scalar), // These can have user-defined impls: Adt(hir_def::AdtId), Dyn(TraitId), ForeignType(ForeignDefId), // These only exist for trait impls Unit, Unnameable, Function(u32), } impl TyFingerprint { /// Creates a TyFingerprint for looking up an inherent impl. Only certain /// types can have inherent impls: if we have some `struct S`, we can have /// an `impl S`, but not `impl &S`. Hence, this will return `None` for /// reference types and such. pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> { let fp = match ty.kind(Interner) { TyKind::Str => TyFingerprint::Str, TyKind::Never => TyFingerprint::Never, TyKind::Slice(..) => TyFingerprint::Slice, TyKind::Array(..) => TyFingerprint::Array, TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, _ => return None, }; Some(fp) } /// Creates a TyFingerprint for looking up a trait impl. pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> { let fp = match ty.kind(Interner) { TyKind::Str => TyFingerprint::Str, TyKind::Never => TyFingerprint::Never, TyKind::Slice(..) => TyFingerprint::Slice, TyKind::Array(..) => TyFingerprint::Array, TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), TyKind::Dyn(_) => ty.dyn_trait().map(TyFingerprint::Dyn)?, TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty), TyKind::Tuple(_, subst) => { let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(Interner)); match first_ty { Some(ty) => return TyFingerprint::for_trait_impl(ty), None => TyFingerprint::Unit, } } TyKind::AssociatedType(_, _) | TyKind::OpaqueType(_, _) | TyKind::FnDef(_, _) | TyKind::Closure(_, _) | TyKind::Generator(..) | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable, TyKind::Function(fn_ptr) => { TyFingerprint::Function(fn_ptr.substitution.0.len(Interner) as u32) } TyKind::Alias(_) | TyKind::Placeholder(_) | TyKind::BoundVar(_) | TyKind::InferenceVar(_, _) | TyKind::Error => return None, }; Some(fp) } } pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ TyFingerprint::Scalar(Scalar::Int(IntTy::I8)), TyFingerprint::Scalar(Scalar::Int(IntTy::I16)), TyFingerprint::Scalar(Scalar::Int(IntTy::I32)), TyFingerprint::Scalar(Scalar::Int(IntTy::I64)), TyFingerprint::Scalar(Scalar::Int(IntTy::I128)), TyFingerprint::Scalar(Scalar::Int(IntTy::Isize)), TyFingerprint::Scalar(Scalar::Uint(UintTy::U8)), TyFingerprint::Scalar(Scalar::Uint(UintTy::U16)), TyFingerprint::Scalar(Scalar::Uint(UintTy::U32)), TyFingerprint::Scalar(Scalar::Uint(UintTy::U64)), TyFingerprint::Scalar(Scalar::Uint(UintTy::U128)), TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)), ]; pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)), TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)), ]; /// Trait impls defined or available in some crate. #[derive(Debug, Eq, PartialEq)] pub struct TraitImpls { // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type. map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, } impl TraitImpls { pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { let _p = profile::span("trait_impls_in_crate_query"); let mut impls = Self { map: FxHashMap::default() }; let crate_def_map = db.crate_def_map(krate); impls.collect_def_map(db, &crate_def_map); impls.shrink_to_fit(); Arc::new(impls) } pub(crate) fn trait_impls_in_block_query( db: &dyn HirDatabase, block: BlockId, ) -> Option<Arc<Self>> { let _p = profile::span("trait_impls_in_block_query"); let mut impls = Self { map: FxHashMap::default() }; let block_def_map = db.block_def_map(block)?; impls.collect_def_map(db, &block_def_map); impls.shrink_to_fit(); Some(Arc::new(impls)) } pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { let _p = profile::span("trait_impls_in_deps_query"); let crate_graph = db.crate_graph(); let mut res = Self { map: FxHashMap::default() }; for krate in crate_graph.transitive_deps(krate) { res.merge(&db.trait_impls_in_crate(krate)); } res.shrink_to_fit(); Arc::new(res) } fn shrink_to_fit(&mut self) { self.map.shrink_to_fit(); self.map.values_mut().for_each(|map| { map.shrink_to_fit(); map.values_mut().for_each(Vec::shrink_to_fit); }); } fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.impls() { let target_trait = match db.impl_trait(impl_id) { Some(tr) => tr.skip_binders().hir_trait_id(), None => continue, }; let self_ty = db.impl_self_ty(impl_id); let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders()); self.map .entry(target_trait) .or_default() .entry(self_ty_fp) .or_default() .push(impl_id); } // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; for konst in collect_unnamed_consts(db, &module_data.scope) { let body = db.body(konst.into()); for (_, block_def_map) in body.blocks(db.upcast()) { self.collect_def_map(db, &block_def_map); } } } } fn merge(&mut self, other: &Self) { for (trait_, other_map) in &other.map { let map = self.map.entry(*trait_).or_default(); for (fp, impls) in other_map { let vec = map.entry(*fp).or_default(); vec.extend(impls); } } } /// Queries all trait impls for the given type. pub fn for_self_ty_without_blanket_impls( &self, fp: TyFingerprint, ) -> impl Iterator<Item = ImplId> + '_ { self.map .values() .flat_map(move |impls| impls.get(&Some(fp)).into_iter()) .flat_map(|it| it.iter().copied()) } /// Queries all impls of the given trait. pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ { self.map .get(&trait_) .into_iter() .flat_map(|map| map.values().flat_map(|v| v.iter().copied())) } /// Queries all impls of `trait_` that may apply to `self_ty`. pub fn for_trait_and_self_ty( &self, trait_: TraitId, self_ty: TyFingerprint, ) -> impl Iterator<Item = ImplId> + '_ { self.map .get(&trait_) .into_iter() .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty)))) .flat_map(|v| v.iter().copied()) } pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied())) } } /// Inherent impls defined in some crate. /// /// Inherent impls can only be defined in the crate that also defines the self type of the impl /// (note that some primitives are considered to be defined by both libcore and liballoc). /// /// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a /// single crate. #[derive(Debug, Eq, PartialEq)] pub struct InherentImpls { map: FxHashMap<TyFingerprint, 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 crate_def_map = db.crate_def_map(krate); impls.collect_def_map(db, &crate_def_map); impls.shrink_to_fit(); Arc::new(impls) } pub(crate) fn inherent_impls_in_block_query( db: &dyn HirDatabase, block: BlockId, ) -> Option<Arc<Self>> { let mut impls = Self { map: FxHashMap::default() }; if let Some(block_def_map) = db.block_def_map(block) { impls.collect_def_map(db, &block_def_map); impls.shrink_to_fit(); return Some(Arc::new(impls)); } None } fn shrink_to_fit(&mut self) { self.map.values_mut().for_each(Vec::shrink_to_fit); self.map.shrink_to_fit(); } fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.impls() { let data = db.impl_data(impl_id); if data.target_trait.is_some() { continue; } 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); } // `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. // const _: () = { ... }; for konst in collect_unnamed_consts(db, &module_data.scope) { let body = db.body(konst.into()); for (_, block_def_map) in body.blocks(db.upcast()) { self.collect_def_map(db, &block_def_map); } } } } pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { match TyFingerprint::for_inherent_impl(self_ty) { Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), None => &[], } } pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { self.map.values().flat_map(|v| v.iter().copied()) } } pub fn inherent_impl_crates_query( db: &dyn HirDatabase, krate: CrateId, fp: TyFingerprint, ) -> ArrayVec<CrateId, 2> { let _p = profile::span("inherent_impl_crates_query"); let mut res = ArrayVec::new(); let crate_graph = db.crate_graph(); for krate in crate_graph.transitive_deps(krate) { if res.is_full() { // we don't currently look for or store more than two crates here, // so don't needlessly look at more crates than necessary. break; } let impls = db.inherent_impls_in_crate(krate); if impls.map.get(&fp).map_or(false, |v| !v.is_empty()) { res.push(krate); } } res } fn collect_unnamed_consts<'a>( db: &'a dyn HirDatabase, scope: &'a ItemScope, ) -> impl Iterator<Item = ConstId> + 'a { let unnamed_consts = scope.unnamed_consts(); // FIXME: Also treat consts named `_DERIVE_*` as unnamed, since synstructure generates those. // Should be removed once synstructure stops doing that. let synstructure_hack_consts = scope.values().filter_map(|(item, _)| match item { ModuleDefId::ConstId(id) => { let loc = id.lookup(db.upcast()); let item_tree = loc.id.item_tree(db.upcast()); if item_tree[loc.id.value] .name .as_ref() .map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_")) { Some(id) } else { None } } _ => None, }); unnamed_consts.chain(synstructure_hack_consts) } pub fn def_crates( db: &dyn HirDatabase, ty: &Ty, cur_crate: CrateId, ) -> Option<ArrayVec<CrateId, 2>> { let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect()); let fp = TyFingerprint::for_inherent_impl(ty); match ty.kind(Interner) { TyKind::Adt(AdtId(def_id), _) => mod_to_crate_ids(def_id.module(db.upcast())), TyKind::Foreign(id) => { mod_to_crate_ids(from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast())) } TyKind::Dyn(_) => ty .dyn_trait() .and_then(|trait_| mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))), // for primitives, there may be impls in various places (core and alloc // mostly). We just check the whole crate graph for crates with impls // (cached behind a query). TyKind::Scalar(_) | TyKind::Str | TyKind::Slice(_) | TyKind::Array(..) | TyKind::Raw(..) => { Some(db.inherent_impl_crates(cur_crate, fp.expect("fingerprint for primitive"))) } _ => return None, } } /// Look up the method with the given name. pub(crate) fn lookup_method( ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: &Name, ) -> Option<(ReceiverAdjustments, FunctionId)> { iterate_method_candidates( ty, db, env, traits_in_scope, visible_from_module, Some(name), LookupMode::MethodCall, |adjustments, f| match f { AssocItemId::FunctionId(f) => Some((adjustments, f)), _ => None, }, ) } /// Whether we're looking up a dotted method call (like `v.len()`) or a path /// (like `Vec::new`). #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LookupMode { /// Looking up a method call like `v.len()`: We only consider candidates /// that have a `self` parameter, and do autoderef. MethodCall, /// Looking up a path like `Vec::new` or `Vec::default`: We consider all /// candidates including associated constants, but don't do autoderef. Path, } #[derive(Clone, Copy)] pub enum VisibleFromModule { /// Filter for results that are visible from the given module Filter(ModuleId), /// Include impls from the given block. IncludeBlock(BlockId), /// Do nothing special in regards visibility None, } impl From<Option<ModuleId>> for VisibleFromModule { fn from(module: Option<ModuleId>) -> Self { match module { Some(module) => Self::Filter(module), None => Self::None, } } } impl From<Option<BlockId>> for VisibleFromModule { fn from(block: Option<BlockId>) -> Self { match block { Some(block) => Self::IncludeBlock(block), None => Self::None, } } } #[derive(Debug, Clone, Default)] pub struct ReceiverAdjustments { autoref: Option<Mutability>, autoderefs: usize, unsize_array: bool, } impl ReceiverAdjustments { pub(crate) fn apply(&self, table: &mut InferenceTable, ty: Ty) -> (Ty, Vec<Adjustment>) { let mut ty = ty; let mut adjust = Vec::new(); for _ in 0..self.autoderefs { match autoderef::autoderef_step(table, ty.clone()) { None => { never!("autoderef not possible for {:?}", ty); ty = TyKind::Error.intern(Interner); break; } Some((kind, new_ty)) => { ty = new_ty.clone(); adjust.push(Adjustment { kind: Adjust::Deref(match kind { // FIXME should we know the mutability here? AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)), AutoderefKind::Builtin => None, }), target: new_ty, }); } } } if self.unsize_array { ty = match ty.kind(Interner) { TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner), _ => { never!("unsize_array with non-array {:?}", ty); ty } }; // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference adjust.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: ty.clone(), }); } if let Some(m) = self.autoref { ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner); adjust .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() }); } (ty, adjust) } fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments { Self { autoref: Some(m), ..*self } } } // This would be nicer if it just returned an iterator, but that runs into // lifetime problems, because we need to borrow temp `CrateImplDefs`. // FIXME add a context type here? pub(crate) fn iterate_method_candidates<T>( ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: Option<&Name>, mode: LookupMode, mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>, ) -> Option<T> { let mut slot = None; iterate_method_candidates_dyn( ty, db, env, traits_in_scope, visible_from_module, name, mode, &mut |adj, item| { assert!(slot.is_none()); if let Some(it) = callback(adj, item) { slot = Some(it); return ControlFlow::Break(()); } ControlFlow::Continue(()) }, ); slot } pub fn iterate_path_candidates( ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: Option<&Name>, callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { iterate_method_candidates_dyn( ty, db, env, traits_in_scope, visible_from_module, name, LookupMode::Path, // the adjustments are not relevant for path lookup &mut |_, id| callback(id), ) } pub fn iterate_method_candidates_dyn( ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: Option<&Name>, mode: LookupMode, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { match mode { LookupMode::MethodCall => { // For method calls, rust first does any number of autoderef, and // then one autoref (i.e. when the method takes &self or &mut self). // Note that when we've got a receiver like &S, even if the method // we find in the end takes &self, we still do the autoderef step // (just as rustc does an autoderef and then autoref again). // We have to be careful about the order we're looking at candidates // in here. Consider the case where we're resolving `x.clone()` // where `x: &Vec<_>`. This resolves to the clone method with self // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where // the receiver type exactly matches before cases where we have to // do autoref. But in the autoderef steps, the `&_` self type comes // up *before* the `Vec<_>` self type. // // On the other hand, we don't want to just pick any by-value method // before any by-autoref method; it's just that we need to consider // the methods by autoderef order of *receiver types*, not *self // types*. let mut table = InferenceTable::new(db, env.clone()); let ty = table.instantiate_canonical(ty.clone()); let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| { iterate_method_candidates_with_autoref( &receiver_ty, adj, db, env.clone(), traits_in_scope, visible_from_module, name, callback, ) }); result } LookupMode::Path => { // No autoderef for path lookups iterate_method_candidates_for_self_ty( ty, db, env, traits_in_scope, visible_from_module, name, callback, ) } } } fn iterate_method_candidates_with_autoref( receiver_ty: &Canonical<Ty>, first_adjustment: ReceiverAdjustments, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: Option<&Name>, mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) { // don't try to resolve methods on unknown types return ControlFlow::Continue(()); } iterate_method_candidates_by_receiver( receiver_ty, first_adjustment.clone(), db, env.clone(), traits_in_scope, visible_from_module, name, &mut callback, )?; let refed = Canonical { value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone()) .intern(Interner), binders: receiver_ty.binders.clone(), }; iterate_method_candidates_by_receiver( &refed, first_adjustment.with_autoref(Mutability::Not), db, env.clone(), traits_in_scope, visible_from_module, name, &mut callback, )?; let ref_muted = Canonical { value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone()) .intern(Interner), binders: receiver_ty.binders.clone(), }; iterate_method_candidates_by_receiver( &ref_muted, first_adjustment.with_autoref(Mutability::Mut), db, env, traits_in_scope, visible_from_module, name, &mut callback, ) } fn iterate_method_candidates_by_receiver( receiver_ty: &Canonical<Ty>, receiver_adjustments: ReceiverAdjustments, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: Option<&Name>, mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { let mut table = InferenceTable::new(db, env); let receiver_ty = table.instantiate_canonical(receiver_ty.clone()); let snapshot = table.snapshot(); // We're looking for methods with *receiver* type receiver_ty. These could // be found in any of the derefs of receiver_ty, so we have to go through // that. let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone()); while let Some((self_ty, _)) = autoderef.next() { iterate_inherent_methods( &self_ty, &mut autoderef.table, name, Some(&receiver_ty), Some(receiver_adjustments.clone()), visible_from_module, &mut callback, )? } table.rollback_to(snapshot); let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone()); while let Some((self_ty, _)) = autoderef.next() { iterate_trait_method_candidates( &self_ty, &mut autoderef.table, traits_in_scope, name, Some(&receiver_ty), Some(receiver_adjustments.clone()), &mut callback, )? } ControlFlow::Continue(()) } fn iterate_method_candidates_for_self_ty( self_ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, traits_in_scope: &FxHashSet<TraitId>, visible_from_module: VisibleFromModule, name: Option<&Name>, mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { let mut table = InferenceTable::new(db, env); let self_ty = table.instantiate_canonical(self_ty.clone()); iterate_inherent_methods( &self_ty, &mut table, name, None, None, visible_from_module, &mut callback, )?; iterate_trait_method_candidates( &self_ty, &mut table, traits_in_scope, name, None, None, callback, ) } fn iterate_trait_method_candidates( self_ty: &Ty, table: &mut InferenceTable, traits_in_scope: &FxHashSet<TraitId>, name: Option<&Name>, receiver_ty: Option<&Ty>, receiver_adjustments: Option<ReceiverAdjustments>, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { let db = table.db; let env = table.trait_env.clone(); let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..)); // if ty is `dyn Trait`, the trait doesn't need to be in scope let inherent_trait = self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_)) // if we have `T: Trait` in the param env, the trait doesn't need to be in scope .then(|| { env.traits_in_scope_from_clauses(self_ty.clone()) .flat_map(|t| all_super_traits(db.upcast(), t)) }) .into_iter() .flatten(); let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied()); let canonical_self_ty = table.canonicalize(self_ty.clone()).value; 'traits: for t in traits { let data = db.trait_data(t); // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during // method resolution, if the receiver is an array, and we're compiling for editions before // 2021. // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for // arrays. if data.skip_array_during_method_dispatch && self_is_array { // FIXME: this should really be using the edition of the method name's span, in case it // comes from a macro if db.crate_graph()[env.krate].edition < Edition::Edition2021 { continue; } } // we'll be lazy about checking whether the type implements the // trait, but if we find out it doesn't, we'll skip the rest of the // iteration let mut known_implemented = false; for &(_, item) in data.items.iter() { // Don't pass a `visible_from_module` down to `is_valid_candidate`, // since only inherent methods should be included into visibility checking. if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) { continue; } if !known_implemented { let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty); if db.trait_solve(env.krate, goal.cast(Interner)).is_none() { continue 'traits; } } known_implemented = true; callback(receiver_adjustments.clone().unwrap_or_default(), item)?; } } ControlFlow::Continue(()) } fn iterate_inherent_methods( self_ty: &Ty, table: &mut InferenceTable, name: Option<&Name>, receiver_ty: Option<&Ty>, receiver_adjustments: Option<ReceiverAdjustments>, visible_from_module: VisibleFromModule, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { let db = table.db; let env = table.trait_env.clone(); let def_crates = match def_crates(db, self_ty, env.krate) { Some(k) => k, None => return ControlFlow::Continue(()), }; let (module, block) = match visible_from_module { VisibleFromModule::Filter(module) => (Some(module), module.containing_block()), VisibleFromModule::IncludeBlock(block) => (None, Some(block)), VisibleFromModule::None => (None, None), }; if let Some(block_id) = block { if let Some(impls) = db.inherent_impls_in_block(block_id) { impls_for_self_ty( &impls, self_ty, table, name, receiver_ty, receiver_adjustments.clone(), module, callback, )?; } } for krate in def_crates { let impls = db.inherent_impls_in_crate(krate); impls_for_self_ty( &impls, self_ty, table, name, receiver_ty, receiver_adjustments.clone(), module, callback, )?; } return ControlFlow::Continue(()); fn impls_for_self_ty( impls: &InherentImpls, self_ty: &Ty, table: &mut InferenceTable, name: Option<&Name>, receiver_ty: Option<&Ty>, receiver_adjustments: Option<ReceiverAdjustments>, visible_from_module: Option<ModuleId>, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, ) -> ControlFlow<()> { let db = table.db; let impls_for_self_ty = impls.for_self_ty(self_ty); for &impl_def in impls_for_self_ty { for &item in &db.impl_data(impl_def).items { if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module) { continue; } callback(receiver_adjustments.clone().unwrap_or_default(), item)?; } } ControlFlow::Continue(()) } } /// Returns the receiver type for the index trait call. pub fn resolve_indexing_op( db: &dyn HirDatabase, env: Arc<TraitEnvironment>, ty: Canonical<Ty>, index_trait: TraitId, ) -> Option<ReceiverAdjustments> { let mut table = InferenceTable::new(db, env.clone()); let ty = table.instantiate_canonical(ty); let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); for (ty, adj) in deref_chain.into_iter().zip(adj) { let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); if db.trait_solve(env.krate, goal.cast(Interner)).is_some() { return Some(adj); } } None } fn is_valid_candidate( table: &mut InferenceTable, name: Option<&Name>, receiver_ty: Option<&Ty>, item: AssocItemId, self_ty: &Ty, visible_from_module: Option<ModuleId>, ) -> bool { let db = table.db; match item { AssocItemId::FunctionId(m) => { let data = db.function_data(m); if let Some(name) = name { if &data.name != name { return false; } } table.run_in_snapshot(|table| { let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build(); let expected_self_ty = match m.lookup(db.upcast()).container { ItemContainerId::TraitId(_) => { subst.at(Interner, 0).assert_ty_ref(Interner).clone() } ItemContainerId::ImplId(impl_id) => { subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner) } // We should only get called for associated items (impl/trait) ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => { unreachable!() } }; if !table.unify(&expected_self_ty, &self_ty) { return false; } if let Some(receiver_ty) = receiver_ty { if !data.has_self_param() { return false; } let sig = db.callable_item_signature(m.into()); let expected_receiver = sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst); let receiver_matches = table.unify(&receiver_ty, &expected_receiver); if !receiver_matches { return false; } } if let Some(from_module) = visible_from_module { if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) { cov_mark::hit!(autoderef_candidate_not_visible); return false; } } true }) } AssocItemId::ConstId(c) => { let data = db.const_data(c); if receiver_ty.is_some() { return false; } if let Some(name) = name { if data.name.as_ref() != Some(name) { return false; } } if let Some(from_module) = visible_from_module { if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) { cov_mark::hit!(const_candidate_not_visible); return false; } } if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container { let self_ty_matches = table.run_in_snapshot(|table| { let subst = TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build(); let expected_self_ty = subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner); table.unify(&expected_self_ty, &self_ty) }); if !self_ty_matches { cov_mark::hit!(const_candidate_self_type_mismatch); return false; } } true } _ => false, } } pub fn implements_trait( ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env.clone(), trait_, ty); let solution = db.trait_solve(env.krate, goal.cast(Interner)); solution.is_some() } pub fn implements_trait_unique( ty: &Canonical<Ty>, db: &dyn HirDatabase, env: Arc<TraitEnvironment>, trait_: TraitId, ) -> bool { let goal = generic_implements_goal(db, env.clone(), trait_, ty); let solution = db.trait_solve(env.krate, goal.cast(Interner)); matches!(solution, Some(crate::Solution::Unique(_))) } /// This creates Substs for a trait with the given Self type and type variables /// for all other parameters, to query Chalk with it. fn generic_implements_goal( db: &dyn HirDatabase, env: Arc<TraitEnvironment>, trait_: TraitId, self_ty: &Canonical<Ty>, ) -> Canonical<InEnvironment<super::DomainGoal>> { let mut kinds = self_ty.binders.interned().to_vec(); let trait_ref = TyBuilder::trait_ref(db, trait_) .push(self_ty.value.clone()) .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) .build(); kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| { let vk = match x.data(Interner) { chalk_ir::GenericArgData::Ty(_) => { chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) } chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, chalk_ir::GenericArgData::Const(c) => { chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) } }; chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) })); let obligation = trait_ref.cast(Interner); Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: InEnvironment::new(&env.env, obligation), } } fn autoderef_method_receiver( table: &mut InferenceTable, ty: Ty, ) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) { let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new()); let mut autoderef = autoderef::Autoderef::new(table, ty); while let Some((ty, derefs)) = autoderef.next() { deref_chain.push(autoderef.table.canonicalize(ty).value); adjustments.push(ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false, }); } // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = ( deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())), adjustments.last().cloned(), ) { let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner); deref_chain.push(Canonical { value: unsized_ty, binders }); adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj }); } (deref_chain, adjustments) }