Auto merge of #102926 - matthiaskrgr:rollup-oe2cdzj, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - #100387 (Check uniqueness of impl items by trait item when applicable.) - #101727 (Stabilize map_first_last) - #101774 (Warn about safety of `fetch_update`) - #102227 (fs::get_path solarish version.) - #102445 (Add `is_empty()` method to `core::ffi::CStr`.) - #102612 (Migrate `codegen_ssa` to diagnostics structs - [Part 1]) - #102685 (Interpret EH actions properly) - #102869 (Add basename and dirname aliases) - #102889 (rustc_hir: Less error-prone methods for accessing `PartialRes` resolution) - #102893 (Fix ICE #102878) - #102912 (⬆️ rust-analyzer) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
db0597f561
163 changed files with 3797 additions and 1356 deletions
|
@ -205,13 +205,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let static_def_id = self
|
||||
.resolver
|
||||
.get_partial_res(sym.id)
|
||||
.filter(|res| res.unresolved_segments() == 0)
|
||||
.and_then(|res| {
|
||||
if let Res::Def(DefKind::Static(_), def_id) = res.base_res() {
|
||||
Some(def_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.and_then(|res| res.full_res())
|
||||
.and_then(|res| match res {
|
||||
Res::Def(DefKind::Static(_), def_id) => Some(def_id),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if let Some(def_id) = static_def_id {
|
||||
|
|
|
@ -1044,9 +1044,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
if partial_res.unresolved_segments() == 0
|
||||
&& !partial_res.base_res().expected_in_tuple_struct_pat()
|
||||
{
|
||||
if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -1066,9 +1064,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a unit struct/variant pattern?
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
if partial_res.unresolved_segments() == 0
|
||||
&& !partial_res.base_res().expected_in_unit_struct_pat()
|
||||
{
|
||||
if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -947,7 +947,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
},
|
||||
trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
|
||||
trait_item_def_id: self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.map(|r| r.expect_full_res().def_id()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1349,9 +1352,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
match self
|
||||
.resolver
|
||||
.get_partial_res(bound_pred.bounded_ty.id)
|
||||
.map(|d| (d.base_res(), d.unresolved_segments()))
|
||||
.and_then(|r| r.full_res())
|
||||
{
|
||||
Some((Res::Def(DefKind::TyParam, def_id), 0))
|
||||
Some(Res::Def(DefKind::TyParam, def_id))
|
||||
if bound_pred.bound_generic_params.is_empty() =>
|
||||
{
|
||||
generics
|
||||
|
|
|
@ -175,12 +175,7 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
|
|||
return None;
|
||||
}
|
||||
|
||||
let partial_res = self.partial_res_map.get(&expr.id)?;
|
||||
if partial_res.unresolved_segments() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() {
|
||||
if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? {
|
||||
// We only support cross-crate argument rewriting. Uses
|
||||
// within the same crate should be updated to use the new
|
||||
// const generics style.
|
||||
|
@ -753,12 +748,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
|
||||
self.resolver.get_partial_res(id).map_or(Res::Err, |pr| {
|
||||
if pr.unresolved_segments() != 0 {
|
||||
panic!("path not fully resolved: {:?}", pr);
|
||||
}
|
||||
pr.base_res()
|
||||
})
|
||||
self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
|
||||
}
|
||||
|
||||
fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
|
||||
|
@ -1138,8 +1128,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// type and value namespaces. If we resolved the path in the value namespace, we
|
||||
// transform it into a generic const argument.
|
||||
TyKind::Path(ref qself, ref path) => {
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
|
||||
let res = partial_res.base_res();
|
||||
if let Some(res) = self
|
||||
.resolver
|
||||
.get_partial_res(ty.id)
|
||||
.and_then(|partial_res| partial_res.full_res())
|
||||
{
|
||||
if !res.matches_ns(Namespace::TypeNS) {
|
||||
debug!(
|
||||
"lower_generic_arg: Lowering type argument as const argument: {:?}",
|
||||
|
@ -1206,8 +1199,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// by `ty_path`.
|
||||
if qself.is_none()
|
||||
&& let Some(partial_res) = self.resolver.get_partial_res(t.id)
|
||||
&& partial_res.unresolved_segments() == 0
|
||||
&& let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
|
||||
&& let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
|
||||
{
|
||||
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
|
||||
let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
|
||||
|
|
|
@ -239,7 +239,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ident: Ident,
|
||||
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
|
||||
) -> hir::PatKind<'hir> {
|
||||
match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
|
||||
match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
res @ (None | Some(Res::Local(_))) => {
|
||||
let canonical_id = match res {
|
||||
|
|
|
@ -29,11 +29,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
let base_res = partial_res.base_res();
|
||||
let unresolved_segments = partial_res.unresolved_segments();
|
||||
|
||||
let path_span_lo = p.span.shrink_to_lo();
|
||||
let proj_start = p.segments.len() - partial_res.unresolved_segments();
|
||||
let proj_start = p.segments.len() - unresolved_segments;
|
||||
let path = self.arena.alloc(hir::Path {
|
||||
res: self.lower_res(partial_res.base_res()),
|
||||
res: self.lower_res(base_res),
|
||||
segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
|
||||
|(i, segment)| {
|
||||
let param_mode = match (qself_position, param_mode) {
|
||||
|
@ -46,7 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
_ => param_mode,
|
||||
};
|
||||
|
||||
let parenthesized_generic_args = match partial_res.base_res() {
|
||||
let parenthesized_generic_args = match base_res {
|
||||
// `a::b::Trait(Args)`
|
||||
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
|
||||
ParenthesizedGenericArgs::Ok
|
||||
|
@ -83,7 +85,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
// Simple case, either no projections, or only fully-qualified.
|
||||
// E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
|
||||
if partial_res.unresolved_segments() == 0 {
|
||||
if unresolved_segments == 0 {
|
||||
return hir::QPath::Resolved(qself, path);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,9 @@ use super::command::Command;
|
|||
use super::linker::{self, Linker};
|
||||
use super::metadata::{create_rmeta_file, MetadataPosition};
|
||||
use super::rpath::{self, RPathConfig};
|
||||
use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
|
||||
use crate::{
|
||||
errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
|
||||
};
|
||||
|
||||
use cc::windows_registry;
|
||||
use regex::Regex;
|
||||
|
@ -93,7 +95,7 @@ pub fn link_binary<'a>(
|
|||
let tmpdir = TempFileBuilder::new()
|
||||
.prefix("rustc")
|
||||
.tempdir()
|
||||
.unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
|
||||
.unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
|
||||
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
|
||||
let out_filename = out_filename(
|
||||
sess,
|
||||
|
@ -208,7 +210,7 @@ pub fn link_binary<'a>(
|
|||
pub fn each_linked_rlib(
|
||||
info: &CrateInfo,
|
||||
f: &mut dyn FnMut(CrateNum, &Path),
|
||||
) -> Result<(), String> {
|
||||
) -> Result<(), errors::LinkRlibError> {
|
||||
let crates = info.used_crates.iter();
|
||||
let mut fmts = None;
|
||||
for (ty, list) in info.dependency_formats.iter() {
|
||||
|
@ -224,26 +226,23 @@ pub fn each_linked_rlib(
|
|||
}
|
||||
}
|
||||
let Some(fmts) = fmts else {
|
||||
return Err("could not find formats for rlibs".to_string());
|
||||
return Err(errors::LinkRlibError::MissingFormat);
|
||||
};
|
||||
for &cnum in crates {
|
||||
match fmts.get(cnum.as_usize() - 1) {
|
||||
Some(&Linkage::NotLinked | &Linkage::IncludedFromDylib) => continue,
|
||||
Some(_) => {}
|
||||
None => return Err("could not find formats for rlibs".to_string()),
|
||||
None => return Err(errors::LinkRlibError::MissingFormat),
|
||||
}
|
||||
let name = info.crate_name[&cnum];
|
||||
let crate_name = info.crate_name[&cnum];
|
||||
let used_crate_source = &info.used_crate_source[&cnum];
|
||||
if let Some((path, _)) = &used_crate_source.rlib {
|
||||
f(cnum, &path);
|
||||
} else {
|
||||
if used_crate_source.rmeta.is_some() {
|
||||
return Err(format!(
|
||||
"could not find rlib for: `{}`, found rmeta (metadata) file",
|
||||
name
|
||||
));
|
||||
return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
|
||||
} else {
|
||||
return Err(format!("could not find rlib for: `{}`", name));
|
||||
return Err(errors::LinkRlibError::NotFound { crate_name });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,10 +339,7 @@ fn link_rlib<'a>(
|
|||
// -whole-archive and it isn't clear how we can currently handle such a
|
||||
// situation correctly.
|
||||
// See https://github.com/rust-lang/rust/issues/88085#issuecomment-901050897
|
||||
sess.err(
|
||||
"the linking modifiers `+bundle` and `+whole-archive` are not compatible \
|
||||
with each other when generating rlibs",
|
||||
);
|
||||
sess.emit_err(errors::IncompatibleLinkingModifiers);
|
||||
}
|
||||
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
|
||||
NativeLibKind::Static { bundle: Some(false), .. }
|
||||
|
@ -365,12 +361,8 @@ fn link_rlib<'a>(
|
|||
));
|
||||
continue;
|
||||
}
|
||||
ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|e| {
|
||||
sess.fatal(&format!(
|
||||
"failed to add native library {}: {}",
|
||||
location.to_string_lossy(),
|
||||
e
|
||||
));
|
||||
ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {
|
||||
sess.emit_fatal(errors::AddNativeLibrary { library_path: location, error });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -385,8 +377,8 @@ fn link_rlib<'a>(
|
|||
tmpdir.as_ref(),
|
||||
);
|
||||
|
||||
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| {
|
||||
sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e));
|
||||
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
|
||||
sess.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -451,14 +443,11 @@ fn collate_raw_dylibs(
|
|||
// FIXME: when we add support for ordinals, figure out if we need to do anything
|
||||
// if we have two DllImport values with the same name but different ordinals.
|
||||
if import.calling_convention != old_import.calling_convention {
|
||||
sess.span_err(
|
||||
import.span,
|
||||
&format!(
|
||||
"multiple declarations of external function `{}` from \
|
||||
library `{}` have different calling conventions",
|
||||
import.name, name,
|
||||
),
|
||||
);
|
||||
sess.emit_err(errors::MultipleExternalFuncDecl {
|
||||
span: import.span,
|
||||
function: import.name,
|
||||
library_name: &name,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -560,7 +549,7 @@ fn link_staticlib<'a>(
|
|||
all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned());
|
||||
});
|
||||
if let Err(e) = res {
|
||||
sess.fatal(&e);
|
||||
sess.emit_fatal(e);
|
||||
}
|
||||
|
||||
ab.build(out_filename);
|
||||
|
@ -673,9 +662,7 @@ fn link_dwarf_object<'a>(
|
|||
}) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
sess.struct_err("linking dwarf objects with thorin failed")
|
||||
.note(&format!("{:?}", e))
|
||||
.emit();
|
||||
sess.emit_err(errors::ThorinErrorWrapper(e));
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
}
|
||||
|
@ -879,23 +866,14 @@ fn link_natively<'a>(
|
|||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
let escaped_output = escape_string(&output);
|
||||
let mut err = sess.struct_err(&format!(
|
||||
"linking with `{}` failed: {}",
|
||||
linker_path.display(),
|
||||
prog.status
|
||||
));
|
||||
err.note(&format!("{:?}", &cmd)).note(&escaped_output);
|
||||
if escaped_output.contains("undefined reference to") {
|
||||
err.help(
|
||||
"some `extern` functions couldn't be found; some native libraries may \
|
||||
need to be installed or have their path specified",
|
||||
);
|
||||
err.note("use the `-l` flag to specify native libraries to link");
|
||||
err.note("use the `cargo:rustc-link-lib` directive to specify the native \
|
||||
libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)");
|
||||
}
|
||||
err.emit();
|
||||
|
||||
// FIXME: Add UI tests for this error.
|
||||
let err = errors::LinkingFailed {
|
||||
linker_path: &linker_path,
|
||||
exit_status: prog.status,
|
||||
command: &cmd,
|
||||
escaped_output: &escaped_output,
|
||||
};
|
||||
sess.diagnostic().emit_err(err);
|
||||
// If MSVC's `link.exe` was expected but the return code
|
||||
// is not a Microsoft LNK error then suggest a way to fix or
|
||||
// install the Visual Studio build tools.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use super::command::Command;
|
||||
use super::symbol_export;
|
||||
use crate::errors;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
|
@ -434,11 +435,11 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
// FIXME(81490): ld64 doesn't support these flags but macOS 11
|
||||
// has -needed-l{} / -needed_library {}
|
||||
// but we have no way to detect that here.
|
||||
self.sess.warn("`as-needed` modifier not implemented yet for ld64");
|
||||
self.sess.emit_warning(errors::Ld64UnimplementedModifier);
|
||||
} else if self.is_gnu && !self.sess.target.is_like_windows {
|
||||
self.linker_arg("--no-as-needed");
|
||||
} else {
|
||||
self.sess.warn("`as-needed` modifier not supported for current linker");
|
||||
self.sess.emit_warning(errors::LinkerUnsupportedModifier);
|
||||
}
|
||||
}
|
||||
self.hint_dynamic();
|
||||
|
@ -492,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
|
||||
// flag but we have no way to detect that here.
|
||||
// self.cmd.arg("-needed_framework").arg(framework);
|
||||
self.sess.warn("`as-needed` modifier not implemented yet for ld64");
|
||||
self.sess.emit_warning(errors::Ld64UnimplementedModifier);
|
||||
}
|
||||
self.cmd.arg("-framework").arg(framework);
|
||||
}
|
||||
|
@ -665,8 +666,8 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
writeln!(f, "_{}", sym)?;
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
|
||||
if let Err(error) = res {
|
||||
self.sess.emit_fatal(errors::LibDefWriteFailure { error });
|
||||
}
|
||||
} else if is_windows {
|
||||
let res: io::Result<()> = try {
|
||||
|
@ -680,8 +681,8 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
writeln!(f, " {}", symbol)?;
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write list.def file: {}", e));
|
||||
if let Err(error) = res {
|
||||
self.sess.emit_fatal(errors::LibDefWriteFailure { error });
|
||||
}
|
||||
} else {
|
||||
// Write an LD version script
|
||||
|
@ -697,8 +698,8 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
}
|
||||
writeln!(f, "\n local:\n *;\n}};")?;
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write version script: {}", e));
|
||||
if let Err(error) = res {
|
||||
self.sess.emit_fatal(errors::VersionScriptWriteFailure { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -915,9 +916,8 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
self.cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
self.sess
|
||||
.warn(&format!("error enumerating natvis directory: {}", err));
|
||||
Err(error) => {
|
||||
self.sess.emit_warning(errors::NoNatvisDirectory { error });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -971,8 +971,8 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
writeln!(f, " {}", symbol)?;
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
|
||||
if let Err(error) = res {
|
||||
self.sess.emit_fatal(errors::LibDefWriteFailure { error });
|
||||
}
|
||||
let mut arg = OsString::from("/DEF:");
|
||||
arg.push(path);
|
||||
|
@ -1435,7 +1435,7 @@ impl<'a> Linker for L4Bender<'a> {
|
|||
|
||||
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
|
||||
// ToDo, not implemented, copy from GCC
|
||||
self.sess.warn("exporting symbols not implemented yet for L4Bender");
|
||||
self.sess.emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1727,8 +1727,8 @@ impl<'a> Linker for BpfLinker<'a> {
|
|||
writeln!(f, "{}", sym)?;
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write symbols file: {}", e));
|
||||
if let Err(error) = res {
|
||||
self.sess.emit_fatal(errors::SymbolFileWriteFailure { error });
|
||||
} else {
|
||||
self.cmd.arg("--export-symbols").arg(&path);
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ use super::link::{self, ensure_removed};
|
|||
use super::lto::{self, SerializedModule};
|
||||
use super::symbol_export::symbol_name_for_instance_in_crate;
|
||||
|
||||
use crate::errors;
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||
};
|
||||
|
||||
use crate::traits::*;
|
||||
use jobserver::{Acquired, Client};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
|
@ -530,7 +530,7 @@ fn produce_final_output_artifacts(
|
|||
// Produce final compile outputs.
|
||||
let copy_gracefully = |from: &Path, to: &Path| {
|
||||
if let Err(e) = fs::copy(from, to) {
|
||||
sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
|
||||
sess.emit_err(errors::CopyPath::new(from, to, e));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -546,7 +546,7 @@ fn produce_final_output_artifacts(
|
|||
ensure_removed(sess.diagnostic(), &path);
|
||||
}
|
||||
} else {
|
||||
let ext = crate_output
|
||||
let extension = crate_output
|
||||
.temp_path(output_type, None)
|
||||
.extension()
|
||||
.unwrap()
|
||||
|
@ -557,19 +557,11 @@ fn produce_final_output_artifacts(
|
|||
if crate_output.outputs.contains_key(&output_type) {
|
||||
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.warn(&format!(
|
||||
"ignoring emit path because multiple .{} files \
|
||||
were produced",
|
||||
ext
|
||||
));
|
||||
sess.emit_warning(errors::IgnoringEmitPath { extension });
|
||||
} else if crate_output.single_output_file.is_some() {
|
||||
// 3) Multiple codegen units, with `-o some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.warn(&format!(
|
||||
"ignoring -o because multiple .{} files \
|
||||
were produced",
|
||||
ext
|
||||
));
|
||||
sess.emit_warning(errors::IgnoringOutput { extension });
|
||||
} else {
|
||||
// 4) Multiple codegen units, but no explicit name. We
|
||||
// just leave the `foo.0.x` files in place.
|
||||
|
@ -880,14 +872,12 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
|||
);
|
||||
match link_or_copy(&source_file, &output_path) {
|
||||
Ok(_) => Some(output_path),
|
||||
Err(err) => {
|
||||
let diag_handler = cgcx.create_diag_handler();
|
||||
diag_handler.err(&format!(
|
||||
"unable to copy {} to {}: {}",
|
||||
source_file.display(),
|
||||
output_path.display(),
|
||||
err
|
||||
));
|
||||
Err(error) => {
|
||||
cgcx.create_diag_handler().emit_err(errors::CopyPathBuf {
|
||||
source_file,
|
||||
output_path,
|
||||
error,
|
||||
});
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
353
compiler/rustc_codegen_ssa/src/errors.rs
Normal file
353
compiler/rustc_codegen_ssa/src/errors.rs
Normal file
|
@ -0,0 +1,353 @@
|
|||
//! Errors emitted by codegen_ssa
|
||||
|
||||
use crate::back::command::Command;
|
||||
use rustc_errors::{
|
||||
fluent, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
|
||||
IntoDiagnosticArg,
|
||||
};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::borrow::Cow;
|
||||
use std::io::Error;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::ExitStatus;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::lib_def_write_failure)]
|
||||
pub struct LibDefWriteFailure {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::version_script_write_failure)]
|
||||
pub struct VersionScriptWriteFailure {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::symbol_file_write_failure)]
|
||||
pub struct SymbolFileWriteFailure {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::ld64_unimplemented_modifier)]
|
||||
pub struct Ld64UnimplementedModifier;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::linker_unsupported_modifier)]
|
||||
pub struct LinkerUnsupportedModifier;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::L4Bender_exporting_symbols_unimplemented)]
|
||||
pub struct L4BenderExportingSymbolsUnimplemented;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::no_natvis_directory)]
|
||||
pub struct NoNatvisDirectory {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::copy_path_buf)]
|
||||
pub struct CopyPathBuf {
|
||||
pub source_file: PathBuf,
|
||||
pub output_path: PathBuf,
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
// Reports Paths using `Debug` implementation rather than Path's `Display` implementation.
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::copy_path)]
|
||||
pub struct CopyPath<'a> {
|
||||
from: DebugArgPath<'a>,
|
||||
to: DebugArgPath<'a>,
|
||||
error: Error,
|
||||
}
|
||||
|
||||
impl<'a> CopyPath<'a> {
|
||||
pub fn new(from: &'a Path, to: &'a Path, error: Error) -> CopyPath<'a> {
|
||||
CopyPath { from: DebugArgPath(from), to: DebugArgPath(to), error }
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugArgPath<'a>(pub &'a Path);
|
||||
|
||||
impl IntoDiagnosticArg for DebugArgPath<'_> {
|
||||
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self.0)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::ignoring_emit_path)]
|
||||
pub struct IgnoringEmitPath {
|
||||
pub extension: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::ignoring_output)]
|
||||
pub struct IgnoringOutput {
|
||||
pub extension: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::create_temp_dir)]
|
||||
pub struct CreateTempDir {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::incompatible_linking_modifiers)]
|
||||
pub struct IncompatibleLinkingModifiers;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::add_native_library)]
|
||||
pub struct AddNativeLibrary {
|
||||
pub library_path: PathBuf,
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa::multiple_external_func_decl)]
|
||||
pub struct MultipleExternalFuncDecl<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub function: Symbol,
|
||||
pub library_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub enum LinkRlibError {
|
||||
#[diag(codegen_ssa::rlib_missing_format)]
|
||||
MissingFormat,
|
||||
|
||||
#[diag(codegen_ssa::rlib_only_rmeta_found)]
|
||||
OnlyRmetaFound { crate_name: Symbol },
|
||||
|
||||
#[diag(codegen_ssa::rlib_not_found)]
|
||||
NotFound { crate_name: Symbol },
|
||||
}
|
||||
|
||||
pub struct ThorinErrorWrapper(pub thorin::Error);
|
||||
|
||||
impl IntoDiagnostic<'_> for ThorinErrorWrapper {
|
||||
fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut diag;
|
||||
match self.0 {
|
||||
thorin::Error::ReadInput(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_read_input_failure);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseFileKind(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_file_kind);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseObjectFile(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_object_file);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseArchiveFile(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_input_archive_file);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseArchiveMember(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_archive_member);
|
||||
diag
|
||||
}
|
||||
thorin::Error::InvalidInputKind => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_invalid_input_kind);
|
||||
diag
|
||||
}
|
||||
thorin::Error::DecompressData(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_decompress_data);
|
||||
diag
|
||||
}
|
||||
thorin::Error::NamelessSection(_, offset) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_section_without_name);
|
||||
diag.set_arg("offset", format!("0x{:08x}", offset));
|
||||
diag
|
||||
}
|
||||
thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
|
||||
diag =
|
||||
handler.struct_err(fluent::codegen_ssa::thorin_relocation_with_invalid_symbol);
|
||||
diag.set_arg("section", section);
|
||||
diag.set_arg("offset", format!("0x{:08x}", offset));
|
||||
diag
|
||||
}
|
||||
thorin::Error::MultipleRelocations(section, offset) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_relocations);
|
||||
diag.set_arg("section", section);
|
||||
diag.set_arg("offset", format!("0x{:08x}", offset));
|
||||
diag
|
||||
}
|
||||
thorin::Error::UnsupportedRelocation(section, offset) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_unsupported_relocation);
|
||||
diag.set_arg("section", section);
|
||||
diag.set_arg("offset", format!("0x{:08x}", offset));
|
||||
diag
|
||||
}
|
||||
thorin::Error::MissingDwoName(id) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_dwo_name);
|
||||
diag.set_arg("id", format!("0x{:08x}", id));
|
||||
diag
|
||||
}
|
||||
thorin::Error::NoCompilationUnits => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_no_compilation_units);
|
||||
diag
|
||||
}
|
||||
thorin::Error::NoDie => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_no_die);
|
||||
diag
|
||||
}
|
||||
thorin::Error::TopLevelDieNotUnit => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_top_level_die_not_unit);
|
||||
diag
|
||||
}
|
||||
thorin::Error::MissingRequiredSection(section) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_required_section);
|
||||
diag.set_arg("section", section);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseUnitAbbreviations(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_abbreviations);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseUnitAttribute(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_attribute);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseUnitHeader(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit_header);
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseUnit(_) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_unit);
|
||||
diag
|
||||
}
|
||||
thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_incompatible_index_version);
|
||||
diag.set_arg("section", section);
|
||||
diag.set_arg("actual", actual);
|
||||
diag.set_arg("format", format);
|
||||
diag
|
||||
}
|
||||
thorin::Error::OffsetAtIndex(_, index) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_offset_at_index);
|
||||
diag.set_arg("index", index);
|
||||
diag
|
||||
}
|
||||
thorin::Error::StrAtOffset(_, offset) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_str_at_offset);
|
||||
diag.set_arg("offset", format!("0x{:08x}", offset));
|
||||
diag
|
||||
}
|
||||
thorin::Error::ParseIndex(_, section) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_parse_index);
|
||||
diag.set_arg("section", section);
|
||||
diag
|
||||
}
|
||||
thorin::Error::UnitNotInIndex(unit) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_unit_not_in_index);
|
||||
diag.set_arg("unit", format!("0x{:08x}", unit));
|
||||
diag
|
||||
}
|
||||
thorin::Error::RowNotInIndex(_, row) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_row_not_in_index);
|
||||
diag.set_arg("row", row);
|
||||
diag
|
||||
}
|
||||
thorin::Error::SectionNotInRow => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_section_not_in_row);
|
||||
diag
|
||||
}
|
||||
thorin::Error::EmptyUnit(unit) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_empty_unit);
|
||||
diag.set_arg("unit", format!("0x{:08x}", unit));
|
||||
diag
|
||||
}
|
||||
thorin::Error::MultipleDebugInfoSection => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_info_section);
|
||||
diag
|
||||
}
|
||||
thorin::Error::MultipleDebugTypesSection => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_multiple_debug_types_section);
|
||||
diag
|
||||
}
|
||||
thorin::Error::NotSplitUnit => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_not_split_unit);
|
||||
diag
|
||||
}
|
||||
thorin::Error::DuplicateUnit(unit) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_duplicate_unit);
|
||||
diag.set_arg("unit", format!("0x{:08x}", unit));
|
||||
diag
|
||||
}
|
||||
thorin::Error::MissingReferencedUnit(unit) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_missing_referenced_unit);
|
||||
diag.set_arg("unit", format!("0x{:08x}", unit));
|
||||
diag
|
||||
}
|
||||
thorin::Error::NoOutputObjectCreated => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_not_output_object_created);
|
||||
diag
|
||||
}
|
||||
thorin::Error::MixedInputEncodings => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_mixed_input_encodings);
|
||||
diag
|
||||
}
|
||||
thorin::Error::Io(e) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_io);
|
||||
diag.set_arg("error", format!("{e}"));
|
||||
diag
|
||||
}
|
||||
thorin::Error::ObjectRead(e) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_object_read);
|
||||
diag.set_arg("error", format!("{e}"));
|
||||
diag
|
||||
}
|
||||
thorin::Error::ObjectWrite(e) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_object_write);
|
||||
diag.set_arg("error", format!("{e}"));
|
||||
diag
|
||||
}
|
||||
thorin::Error::GimliRead(e) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_read);
|
||||
diag.set_arg("error", format!("{e}"));
|
||||
diag
|
||||
}
|
||||
thorin::Error::GimliWrite(e) => {
|
||||
diag = handler.struct_err(fluent::codegen_ssa::thorin_gimli_write);
|
||||
diag.set_arg("error", format!("{e}"));
|
||||
diag
|
||||
}
|
||||
_ => unimplemented!("Untranslated thorin error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LinkingFailed<'a> {
|
||||
pub linker_path: &'a PathBuf,
|
||||
pub exit_status: ExitStatus,
|
||||
pub command: &'a Command,
|
||||
pub escaped_output: &'a str,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for LinkingFailed<'_> {
|
||||
fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut diag = handler.struct_err(fluent::codegen_ssa::linking_failed);
|
||||
diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
|
||||
diag.set_arg("exit_status", format!("{}", self.exit_status));
|
||||
|
||||
diag.note(format!("{:?}", self.command)).note(self.escaped_output);
|
||||
|
||||
// Trying to match an error from OS linkers
|
||||
// which by now we have no way to translate.
|
||||
if self.escaped_output.contains("undefined reference to") {
|
||||
diag.note(fluent::codegen_ssa::extern_funcs_not_found)
|
||||
.note(fluent::codegen_ssa::specify_libraries_to_link)
|
||||
.note(fluent::codegen_ssa::use_cargo_directive);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#![feature(strict_provenance)]
|
||||
#![feature(int_roundings)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
|
||||
|
@ -43,6 +44,7 @@ pub mod base;
|
|||
pub mod common;
|
||||
pub mod coverageinfo;
|
||||
pub mod debuginfo;
|
||||
pub mod errors;
|
||||
pub mod glue;
|
||||
pub mod meth;
|
||||
pub mod mir;
|
||||
|
|
119
compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
Normal file
119
compiler/rustc_error_messages/locales/en-US/codegen_ssa.ftl
Normal file
|
@ -0,0 +1,119 @@
|
|||
codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
|
||||
|
||||
codegen_ssa_version_script_write_failure = failed to write version script: {$error}
|
||||
|
||||
codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
|
||||
|
||||
codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
|
||||
|
||||
codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
|
||||
|
||||
codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
|
||||
|
||||
codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
|
||||
|
||||
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
|
||||
|
||||
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
|
||||
|
||||
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
|
||||
|
||||
codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
|
||||
|
||||
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
|
||||
|
||||
codegen_ssa_incompatible_linking_modifiers = the linking modifiers `+bundle` and `+whole-archive` are not compatible with each other when generating rlibs
|
||||
|
||||
codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
|
||||
|
||||
codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
|
||||
|
||||
codegen_ssa_rlib_missing_format = could not find formats for rlibs
|
||||
|
||||
codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
|
||||
|
||||
codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
|
||||
|
||||
codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
|
||||
|
||||
codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
|
||||
|
||||
codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
|
||||
|
||||
codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
|
||||
|
||||
codegen_ssa_thorin_read_input_failure = failed to read input file
|
||||
|
||||
codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
|
||||
|
||||
codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
|
||||
|
||||
codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
|
||||
|
||||
codegen_ssa_thorin_parse_archive_member = failed to parse archive member
|
||||
|
||||
codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
|
||||
|
||||
codegen_ssa_thorin_decompress_data = failed to decompress compressed section
|
||||
|
||||
codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
|
||||
|
||||
codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
|
||||
|
||||
codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
|
||||
|
||||
codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
|
||||
|
||||
codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
|
||||
|
||||
codegen_ssa_thorin_no_compilation_units = input object has no compilation units
|
||||
|
||||
codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
|
||||
|
||||
codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
|
||||
|
||||
codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
|
||||
|
||||
codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
|
||||
|
||||
codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute
|
||||
|
||||
codegen_ssa_thorin_parse_unit_header = failed to parse unit header
|
||||
|
||||
codegen_ssa_thorin_parse_unit = failed to parse unit
|
||||
|
||||
codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
|
||||
|
||||
codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
|
||||
|
||||
codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
|
||||
|
||||
codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
|
||||
|
||||
codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
|
||||
|
||||
codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
|
||||
|
||||
codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
|
||||
|
||||
codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
|
||||
|
||||
codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
|
||||
|
||||
codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
|
||||
|
||||
codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
|
||||
|
||||
codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
|
||||
|
||||
codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
|
||||
|
||||
codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
|
||||
|
||||
codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
|
||||
|
||||
codegen_ssa_thorin_io = {$error}
|
||||
codegen_ssa_thorin_object_read = {$error}
|
||||
codegen_ssa_thorin_object_write = {$error}
|
||||
codegen_ssa_thorin_gimli_read = {$error}
|
||||
codegen_ssa_thorin_gimli_write = {$error}
|
|
@ -40,9 +40,10 @@ fluent_messages! {
|
|||
attr => "../locales/en-US/attr.ftl",
|
||||
borrowck => "../locales/en-US/borrowck.ftl",
|
||||
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
||||
codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
|
||||
codegen_ssa => "../locales/en-US/codegen_ssa.ftl",
|
||||
compiletest => "../locales/en-US/compiletest.ftl",
|
||||
const_eval => "../locales/en-US/const_eval.ftl",
|
||||
codegen_gcc => "../locales/en-US/codegen_gcc.ftl",
|
||||
driver => "../locales/en-US/driver.ftl",
|
||||
expand => "../locales/en-US/expand.ftl",
|
||||
hir_analysis => "../locales/en-US/hir_analysis.ftl",
|
||||
|
@ -336,19 +337,6 @@ impl DiagnosticMessage {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that
|
||||
/// this diagnostic message is of the legacy, non-translatable variety. Panics if this
|
||||
/// assumption does not hold.
|
||||
///
|
||||
/// Don't use this - it exists to support some places that do comparison with diagnostic
|
||||
/// strings.
|
||||
pub fn expect_str(&self) -> &str {
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => s,
|
||||
_ => panic!("expected non-translatable diagnostic message"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `From` impl that enables existing diagnostic calls to functions which now take
|
||||
|
|
|
@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
|||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::builtin::{
|
||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
|
@ -68,19 +68,22 @@ fn emit_frag_parse_err(
|
|||
kind: AstFragmentKind,
|
||||
) {
|
||||
// FIXME(davidtwco): avoid depending on the error message text
|
||||
if parser.token == token::Eof && e.message[0].0.expect_str().ends_with(", found `<eof>`") {
|
||||
if parser.token == token::Eof
|
||||
&& let DiagnosticMessage::Str(message) = &e.message[0].0
|
||||
&& message.ends_with(", found `<eof>`")
|
||||
{
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
DiagnosticMessage::Str(format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
message.replace(", found `<eof>`", ""),
|
||||
)),
|
||||
msg.1,
|
||||
);
|
||||
if !e.span.is_dummy() {
|
||||
// early end of macro arm (#52866)
|
||||
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
|
||||
}
|
||||
let msg = &e.message[0];
|
||||
e.message[0] = (
|
||||
rustc_errors::DiagnosticMessage::Str(format!(
|
||||
"macro expansion ends with an incomplete expression: {}",
|
||||
msg.0.expect_str().replace(", found `<eof>`", ""),
|
||||
)),
|
||||
msg.1,
|
||||
);
|
||||
}
|
||||
if e.span.is_dummy() {
|
||||
// Get around lack of span in error (#30128)
|
||||
|
|
|
@ -464,6 +464,16 @@ impl PartialRes {
|
|||
pub fn unresolved_segments(&self) -> usize {
|
||||
self.unresolved_segments
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn full_res(&self) -> Option<Res<NodeId>> {
|
||||
(self.unresolved_segments == 0).then_some(self.base_res)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn expect_full_res(&self) -> Res<NodeId> {
|
||||
self.full_res().expect("unexpected unresolved segments")
|
||||
}
|
||||
}
|
||||
|
||||
/// Different kinds of symbols can coexist even if they share the same textual name.
|
||||
|
|
|
@ -197,6 +197,9 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
|
|||
|
||||
/// Enforce that we do not have two items in an impl with the same name.
|
||||
fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
|
||||
if tcx.impl_trait_ref(impl_def_id).is_some() {
|
||||
return;
|
||||
}
|
||||
let mut seen_type_items = FxHashMap::default();
|
||||
let mut seen_value_items = FxHashMap::default();
|
||||
for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) {
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#![feature(exhaustive_patterns)]
|
||||
#![feature(get_mut_unchecked)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(map_first_last)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(extern_types)]
|
||||
|
|
|
@ -326,7 +326,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
}
|
||||
PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)),
|
||||
PathResult::NonModule(partial_res) => {
|
||||
expected_found_error(partial_res.base_res())
|
||||
expected_found_error(partial_res.expect_full_res())
|
||||
}
|
||||
PathResult::Failed { span, label, suggestion, .. } => {
|
||||
Err(VisResolutionError::FailedToResolve(span, label, suggestion))
|
||||
|
|
|
@ -1050,6 +1050,19 @@ impl<'a> Resolver<'a> {
|
|||
err.span_label(trait_item_span, "item in trait");
|
||||
err
|
||||
}
|
||||
ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => {
|
||||
let mut err = struct_span_err!(
|
||||
self.session,
|
||||
span,
|
||||
E0201,
|
||||
"duplicate definitions with name `{}`:",
|
||||
name,
|
||||
);
|
||||
err.span_label(old_span, "previous definition here");
|
||||
err.span_label(trait_item_span, "item in trait");
|
||||
err.span_label(span, "duplicate definition");
|
||||
err
|
||||
}
|
||||
ResolutionError::InvalidAsmSym => {
|
||||
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
|
||||
err.span_label(span, "is a local variable");
|
||||
|
|
|
@ -641,8 +641,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||
// Check whether we should interpret this as a bare trait object.
|
||||
if qself.is_none()
|
||||
&& let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
|
||||
&& partial_res.unresolved_segments() == 0
|
||||
&& let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
|
||||
&& let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
|
||||
{
|
||||
// This path is actually a bare trait object. In case of a bare `Fn`-trait
|
||||
// object with anonymous lifetimes, we need this rib to correctly place the
|
||||
|
@ -1929,7 +1928,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
match ty.kind {
|
||||
TyKind::ImplicitSelf => true,
|
||||
TyKind::Path(None, _) => {
|
||||
let path_res = self.r.partial_res_map[&ty.id].base_res();
|
||||
let path_res = self.r.partial_res_map[&ty.id].expect_full_res();
|
||||
if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res {
|
||||
return true;
|
||||
}
|
||||
|
@ -1970,7 +1969,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
None
|
||||
}
|
||||
})
|
||||
.map(|res| res.base_res())
|
||||
.map(|res| res.expect_full_res())
|
||||
.filter(|res| {
|
||||
// Permit the types that unambiguously always
|
||||
// result in the same type constructor being used
|
||||
|
@ -2530,7 +2529,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
Finalize::new(trait_ref.ref_id, trait_ref.path.span),
|
||||
);
|
||||
self.diagnostic_metadata.currently_processing_impl_trait = None;
|
||||
if let Some(def_id) = res.base_res().opt_def_id() {
|
||||
if let Some(def_id) = res.expect_full_res().opt_def_id() {
|
||||
new_id = Some(def_id);
|
||||
new_val = Some((self.r.expect_module(def_id), trait_ref.clone()));
|
||||
}
|
||||
|
@ -2618,8 +2617,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
this.with_current_self_type(self_type, |this| {
|
||||
this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
|
||||
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
|
||||
let mut seen_trait_items = Default::default();
|
||||
for item in impl_items {
|
||||
this.resolve_impl_item(&**item);
|
||||
this.resolve_impl_item(&**item, &mut seen_trait_items);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -2633,7 +2633,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
);
|
||||
}
|
||||
|
||||
fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
|
||||
fn resolve_impl_item(
|
||||
&mut self,
|
||||
item: &'ast AssocItem,
|
||||
seen_trait_items: &mut FxHashMap<DefId, Span>,
|
||||
) {
|
||||
use crate::ResolutionError::*;
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(_, ty, default) => {
|
||||
|
@ -2646,6 +2650,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
&item.kind,
|
||||
ValueNS,
|
||||
item.span,
|
||||
seen_trait_items,
|
||||
|i, s, c| ConstNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
|
@ -2686,6 +2691,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
&item.kind,
|
||||
ValueNS,
|
||||
item.span,
|
||||
seen_trait_items,
|
||||
|i, s, c| MethodNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
|
@ -2714,6 +2720,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
&item.kind,
|
||||
TypeNS,
|
||||
item.span,
|
||||
seen_trait_items,
|
||||
|i, s, c| TypeNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
|
@ -2735,6 +2742,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
kind: &AssocItemKind,
|
||||
ns: Namespace,
|
||||
span: Span,
|
||||
seen_trait_items: &mut FxHashMap<DefId, Span>,
|
||||
err: F,
|
||||
) where
|
||||
F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
|
||||
|
@ -2767,7 +2775,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
};
|
||||
|
||||
let res = binding.res();
|
||||
let Res::Def(def_kind, _) = res else { bug!() };
|
||||
let Res::Def(def_kind, id_in_trait) = res else { bug!() };
|
||||
|
||||
match seen_trait_items.entry(id_in_trait) {
|
||||
Entry::Occupied(entry) => {
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::TraitImplDuplicate {
|
||||
name: ident.name,
|
||||
old_span: *entry.get(),
|
||||
trait_item_span: binding.span,
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(span);
|
||||
}
|
||||
};
|
||||
|
||||
match (def_kind, kind) {
|
||||
(DefKind::AssocTy, AssocItemKind::Type(..))
|
||||
| (DefKind::AssocFn, AssocItemKind::Fn(..))
|
||||
|
@ -2859,7 +2885,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
}
|
||||
|
||||
fn is_base_res_local(&self, nid: NodeId) -> bool {
|
||||
matches!(self.r.partial_res_map.get(&nid).map(|res| res.base_res()), Some(Res::Local(..)))
|
||||
matches!(
|
||||
self.r.partial_res_map.get(&nid).map(|res| res.expect_full_res()),
|
||||
Some(Res::Local(..))
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks that all of the arms in an or-pattern have exactly the
|
||||
|
@ -3346,12 +3375,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
source.defer_to_typeck(),
|
||||
finalize,
|
||||
) {
|
||||
Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => {
|
||||
if source.is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err
|
||||
{
|
||||
Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => {
|
||||
if source.is_expected(res) || res == Res::Err {
|
||||
partial_res
|
||||
} else {
|
||||
report_errors(self, Some(partial_res.base_res()))
|
||||
report_errors(self, Some(res))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3559,20 +3587,21 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
};
|
||||
|
||||
if path.len() > 1
|
||||
&& result.base_res() != Res::Err
|
||||
&& let Some(res) = result.full_res()
|
||||
&& res != Res::Err
|
||||
&& path[0].ident.name != kw::PathRoot
|
||||
&& path[0].ident.name != kw::DollarCrate
|
||||
{
|
||||
let unqualified_result = {
|
||||
match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
|
||||
PathResult::NonModule(path_res) => path_res.base_res(),
|
||||
PathResult::NonModule(path_res) => path_res.expect_full_res(),
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
|
||||
module.res().unwrap()
|
||||
}
|
||||
_ => return Ok(Some(result)),
|
||||
}
|
||||
};
|
||||
if result.base_res() == unqualified_result {
|
||||
if res == unqualified_result {
|
||||
let lint = lint::builtin::UNUSED_QUALIFICATIONS;
|
||||
self.r.lint_buffer.buffer_lint(
|
||||
lint,
|
||||
|
|
|
@ -968,11 +968,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else {
|
||||
return false;
|
||||
};
|
||||
if !(matches!(
|
||||
partial_res.base_res(),
|
||||
hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
|
||||
) && partial_res.unresolved_segments() == 0)
|
||||
{
|
||||
if !matches!(
|
||||
partial_res.full_res(),
|
||||
Some(hir::def::Res::Def(hir::def::DefKind::AssocTy, _))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
(ty, position, path)
|
||||
|
@ -986,11 +985,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
let Some(partial_res) = self.r.partial_res_map.get(&peeled_ty.id) else {
|
||||
return false;
|
||||
};
|
||||
if !(matches!(
|
||||
partial_res.base_res(),
|
||||
hir::def::Res::Def(hir::def::DefKind::TyParam, _)
|
||||
) && partial_res.unresolved_segments() == 0)
|
||||
{
|
||||
if !matches!(
|
||||
partial_res.full_res(),
|
||||
Some(hir::def::Res::Def(hir::def::DefKind::TyParam, _))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if let (
|
||||
|
@ -1518,20 +1516,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
{
|
||||
// Look for a field with the same name in the current self_type.
|
||||
if let Some(resolution) = self.r.partial_res_map.get(&node_id) {
|
||||
match resolution.base_res() {
|
||||
Res::Def(DefKind::Struct | DefKind::Union, did)
|
||||
if resolution.unresolved_segments() == 0 =>
|
||||
{
|
||||
if let Some(field_names) = self.r.field_names.get(&did) {
|
||||
if field_names
|
||||
.iter()
|
||||
.any(|&field_name| ident.name == field_name.node)
|
||||
{
|
||||
return Some(AssocSuggestion::Field);
|
||||
}
|
||||
if let Some(Res::Def(DefKind::Struct | DefKind::Union, did)) =
|
||||
resolution.full_res()
|
||||
{
|
||||
if let Some(field_names) = self.r.field_names.get(&did) {
|
||||
if field_names.iter().any(|&field_name| ident.name == field_name.node) {
|
||||
return Some(AssocSuggestion::Field);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,6 +235,8 @@ enum ResolutionError<'a> {
|
|||
trait_item_span: Span,
|
||||
code: rustc_errors::DiagnosticId,
|
||||
},
|
||||
/// Error E0201: multiple impl items for the same trait item.
|
||||
TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
|
||||
/// Inline asm `sym` operand must refer to a `fn` or `static`.
|
||||
InvalidAsmSym,
|
||||
}
|
||||
|
@ -1881,12 +1883,10 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
|
||||
Some(path_res.base_res())
|
||||
PathResult::NonModule(path_res) => path_res.full_res(),
|
||||
PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => {
|
||||
None
|
||||
}
|
||||
PathResult::Module(ModuleOrUniformRoot::ExternPrelude)
|
||||
| PathResult::NonModule(..)
|
||||
| PathResult::Failed { .. } => None,
|
||||
PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -1937,12 +1937,8 @@ impl<'a> Resolver<'a> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let partial_res = self.partial_res_map.get(&expr.id)?;
|
||||
if partial_res.unresolved_segments() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Res::Def(def::DefKind::Fn, def_id) = partial_res.base_res() {
|
||||
let res = self.partial_res_map.get(&expr.id)?.full_res()?;
|
||||
if let Res::Def(def::DefKind::Fn, def_id) = res {
|
||||
// We only support cross-crate argument rewriting. Uses
|
||||
// within the same crate should be updated to use the new
|
||||
// const generics style.
|
||||
|
|
|
@ -590,9 +590,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
let res = if path.len() > 1 {
|
||||
let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
|
||||
Ok(path_res.base_res())
|
||||
}
|
||||
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res),
|
||||
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
|
||||
PathResult::NonModule(..)
|
||||
| PathResult::Indeterminate
|
||||
|
@ -692,9 +690,8 @@ impl<'a> Resolver<'a> {
|
|||
Some(Finalize::new(ast::CRATE_NODE_ID, path_span)),
|
||||
None,
|
||||
) {
|
||||
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
|
||||
let res = path_res.base_res();
|
||||
check_consistency(self, &path, path_span, kind, initial_res, res);
|
||||
PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => {
|
||||
check_consistency(self, &path, path_span, kind, initial_res, res)
|
||||
}
|
||||
path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => {
|
||||
let (span, label) = if let PathResult::Failed { span, label, .. } = path_res {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#![cfg(not(target_os = "android"))]
|
||||
#![feature(btree_drain_filter)]
|
||||
#![feature(iter_next_chunk)]
|
||||
#![feature(map_first_last)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(test)]
|
||||
|
|
|
@ -703,7 +703,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
|
@ -712,7 +711,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// map.insert(2, "a");
|
||||
/// assert_eq!(map.first_key_value(), Some((&1, &"b")));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn first_key_value(&self) -> Option<(&K, &V)>
|
||||
where
|
||||
K: Ord,
|
||||
|
@ -727,7 +726,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
|
@ -741,7 +739,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// assert_eq!(*map.get(&1).unwrap(), "first");
|
||||
/// assert_eq!(*map.get(&2).unwrap(), "b");
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn first_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>>
|
||||
where
|
||||
K: Ord,
|
||||
|
@ -765,7 +763,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// Draining elements in ascending order, while keeping a usable map each iteration.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
|
@ -776,7 +773,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// }
|
||||
/// assert!(map.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn pop_first(&mut self) -> Option<(K, V)>
|
||||
where
|
||||
K: Ord,
|
||||
|
@ -792,7 +789,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
|
@ -800,7 +796,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// map.insert(2, "a");
|
||||
/// assert_eq!(map.last_key_value(), Some((&2, &"a")));
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn last_key_value(&self) -> Option<(&K, &V)>
|
||||
where
|
||||
K: Ord,
|
||||
|
@ -815,7 +811,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
|
@ -829,7 +824,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// assert_eq!(*map.get(&1).unwrap(), "a");
|
||||
/// assert_eq!(*map.get(&2).unwrap(), "last");
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn last_entry(&mut self) -> Option<OccupiedEntry<'_, K, V, A>>
|
||||
where
|
||||
K: Ord,
|
||||
|
@ -853,7 +848,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// Draining elements in descending order, while keeping a usable map each iteration.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map = BTreeMap::new();
|
||||
|
@ -864,7 +858,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
|||
/// }
|
||||
/// assert!(map.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn pop_last(&mut self) -> Option<(K, V)>
|
||||
where
|
||||
K: Ord,
|
||||
|
|
|
@ -786,7 +786,6 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
|
@ -797,7 +796,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// assert_eq!(set.first(), Some(&1));
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn first(&self) -> Option<&T>
|
||||
where
|
||||
T: Ord,
|
||||
|
@ -813,7 +812,6 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
|
@ -824,7 +822,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// assert_eq!(set.last(), Some(&2));
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn last(&self) -> Option<&T>
|
||||
where
|
||||
T: Ord,
|
||||
|
@ -838,7 +836,6 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
|
@ -849,7 +846,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// }
|
||||
/// assert!(set.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn pop_first(&mut self) -> Option<T>
|
||||
where
|
||||
T: Ord,
|
||||
|
@ -863,7 +860,6 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(map_first_last)]
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set = BTreeSet::new();
|
||||
|
@ -874,7 +870,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
|||
/// }
|
||||
/// assert!(set.is_empty());
|
||||
/// ```
|
||||
#[unstable(feature = "map_first_last", issue = "62924")]
|
||||
#[stable(feature = "map_first_last", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn pop_last(&mut self) -> Option<T>
|
||||
where
|
||||
T: Ord,
|
||||
|
|
|
@ -474,6 +474,34 @@ impl CStr {
|
|||
self.inner.as_ptr()
|
||||
}
|
||||
|
||||
/// Returns `true` if `self.to_bytes()` has a length of 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cstr_is_empty)]
|
||||
///
|
||||
/// use std::ffi::CStr;
|
||||
/// # use std::ffi::FromBytesWithNulError;
|
||||
///
|
||||
/// # fn main() { test().unwrap(); }
|
||||
/// # fn test() -> Result<(), FromBytesWithNulError> {
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
|
||||
/// assert!(!cstr.is_empty());
|
||||
///
|
||||
/// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
|
||||
/// assert!(empty_cstr.is_empty());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "cstr_is_empty", issue = "102444")]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
// SAFETY: We know there is at least one byte; for empty strings it
|
||||
// is the NUL terminator.
|
||||
(unsafe { self.inner.get_unchecked(0) }) == &0
|
||||
}
|
||||
|
||||
/// Converts this C string to a byte slice.
|
||||
///
|
||||
/// The returned slice will **not** contain the trailing nul terminator that this C
|
||||
|
|
|
@ -955,6 +955,14 @@ impl AtomicBool {
|
|||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -1422,6 +1430,14 @@ impl<T> AtomicPtr<T> {
|
|||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on pointers.
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -2510,6 +2526,16 @@ macro_rules! atomic_int {
|
|||
/// **Note**: This method is only available on platforms that support atomic operations on
|
||||
#[doc = concat!("[`", $s_int_type, "`].")]
|
||||
///
|
||||
/// # Considerations
|
||||
///
|
||||
/// This method is not magic; it is not provided by the hardware.
|
||||
/// It is implemented in terms of
|
||||
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
|
||||
/// and suffers from the same drawbacks.
|
||||
/// In particular, this method will not circumvent the [ABA Problem].
|
||||
///
|
||||
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
|
|
|
@ -2158,6 +2158,7 @@ impl Path {
|
|||
/// assert_eq!(grand_parent.parent(), None);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(alias = "dirname")]
|
||||
#[must_use]
|
||||
pub fn parent(&self) -> Option<&Path> {
|
||||
let mut comps = self.components();
|
||||
|
@ -2225,6 +2226,7 @@ impl Path {
|
|||
/// assert_eq!(None, Path::new("/").file_name());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(alias = "basename")]
|
||||
#[must_use]
|
||||
pub fn file_name(&self) -> Option<&OsStr> {
|
||||
self.components().next_back().and_then(|p| match p {
|
||||
|
|
|
@ -98,9 +98,8 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
|
|||
}
|
||||
}
|
||||
}
|
||||
// Ip is not present in the table. This should not happen... but it does: issue #35011.
|
||||
// So rather than returning EHAction::Terminate, we do this.
|
||||
Ok(EHAction::None)
|
||||
// Ip is not present in the table. This indicates a nounwind call.
|
||||
Ok(EHAction::Terminate)
|
||||
} else {
|
||||
// SjLj version:
|
||||
// The "IP" is an index into the call-site table, with two exceptions:
|
||||
|
|
|
@ -1172,7 +1172,12 @@ impl FromRawFd for File {
|
|||
|
||||
impl fmt::Debug for File {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(any(target_os = "linux", target_os = "netbsd"))]
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let mut p = PathBuf::from("/proc/self/fd");
|
||||
p.push(&fd.to_string());
|
||||
|
@ -1227,7 +1232,9 @@ impl fmt::Debug for File {
|
|||
target_os = "macos",
|
||||
target_os = "vxworks",
|
||||
all(target_os = "freebsd", target_arch = "x86_64"),
|
||||
target_os = "netbsd"
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "solaris"
|
||||
)))]
|
||||
fn get_path(_fd: c_int) -> Option<PathBuf> {
|
||||
// FIXME(#24570): implement this for other Unix platforms
|
||||
|
|
|
@ -16,4 +16,5 @@ impl Foo for Baz {
|
|||
|
||||
fn main() {
|
||||
let x: Baz::Bar = 5;
|
||||
//~^ ERROR ambiguous associated type
|
||||
}
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
error[E0201]: duplicate definitions with name `Bar`:
|
||||
--> $DIR/associated-item-duplicate-names-3.rs:14:5
|
||||
|
|
||||
LL | type Bar;
|
||||
| --------- item in trait
|
||||
...
|
||||
LL | type Bar = i16;
|
||||
| -------- previous definition of `Bar` here
|
||||
| --------------- previous definition here
|
||||
LL | type Bar = u16;
|
||||
| ^^^^^^^^ duplicate definition
|
||||
| ^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/associated-item-duplicate-names-3.rs:18:12
|
||||
|
|
||||
LL | let x: Baz::Bar = 5;
|
||||
| ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Trait>::Bar`
|
||||
|
||||
For more information about this error, try `rustc --explain E0201`.
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0201, E0223.
|
||||
For more information about an error, try `rustc --explain E0201`.
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
error[E0201]: duplicate definitions with name `Ty`:
|
||||
--> $DIR/associated-item-duplicate-names.rs:11:5
|
||||
|
|
||||
LL | type Ty;
|
||||
| -------- item in trait
|
||||
...
|
||||
LL | type Ty = ();
|
||||
| ------- previous definition of `Ty` here
|
||||
| ------------- previous definition here
|
||||
LL | type Ty = usize;
|
||||
| ^^^^^^^ duplicate definition
|
||||
| ^^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error[E0201]: duplicate definitions with name `BAR`:
|
||||
--> $DIR/associated-item-duplicate-names.rs:13:5
|
||||
|
|
||||
LL | const BAR: u32;
|
||||
| --------------- item in trait
|
||||
...
|
||||
LL | const BAR: u32 = 7;
|
||||
| -------------- previous definition of `BAR` here
|
||||
| ------------------- previous definition here
|
||||
LL | const BAR: u32 = 8;
|
||||
| ^^^^^^^^^^^^^^ duplicate definition
|
||||
| ^^^^^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
error[E0201]: duplicate definitions with name `baz`:
|
||||
--> $DIR/E0201.rs:17:5
|
||||
|
|
||||
LL | fn baz(&self) -> bool;
|
||||
| ---------------------- item in trait
|
||||
...
|
||||
LL | fn baz(&self) -> bool { true }
|
||||
| ------------------------------ previous definition here
|
||||
LL | fn baz(&self) -> bool { self.0 > 5 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error[E0201]: duplicate definitions with name `Quux`:
|
||||
--> $DIR/E0201.rs:18:5
|
||||
|
|
||||
LL | type Quux;
|
||||
| ---------- item in trait
|
||||
...
|
||||
LL | type Quux = u32;
|
||||
| ---------------- previous definition here
|
||||
...
|
||||
LL | type Quux = u32;
|
||||
| ^^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error[E0201]: duplicate definitions with name `bar`:
|
||||
--> $DIR/E0201.rs:5:5
|
||||
|
|
||||
|
@ -6,23 +29,6 @@ LL | fn bar(&self) -> bool { self.0 > 5 }
|
|||
LL | fn bar() {}
|
||||
| ^^^^^^^^ duplicate definition
|
||||
|
||||
error[E0201]: duplicate definitions with name `baz`:
|
||||
--> $DIR/E0201.rs:17:5
|
||||
|
|
||||
LL | fn baz(&self) -> bool { true }
|
||||
| --------------------- previous definition of `baz` here
|
||||
LL | fn baz(&self) -> bool { self.0 > 5 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error[E0201]: duplicate definitions with name `Quux`:
|
||||
--> $DIR/E0201.rs:18:5
|
||||
|
|
||||
LL | type Quux = u32;
|
||||
| --------- previous definition of `Quux` here
|
||||
...
|
||||
LL | type Quux = u32;
|
||||
| ^^^^^^^^^ duplicate definition
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0201`.
|
||||
|
|
26
src/test/ui/hygiene/impl_items-2.rs
Normal file
26
src/test/ui/hygiene/impl_items-2.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
#![feature(decl_macro)]
|
||||
|
||||
trait Trait {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
macro trait_impl() {
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
// Check that we error on multiple impl items that resolve to the same trait item.
|
||||
impl Trait for i32 {
|
||||
trait_impl!();
|
||||
fn foo() {}
|
||||
//~^ ERROR duplicate definitions with name `foo`: [E0201]
|
||||
}
|
||||
|
||||
struct Type;
|
||||
|
||||
// Check that we do not error with inherent impls.
|
||||
impl Type {
|
||||
trait_impl!();
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
15
src/test/ui/hygiene/impl_items-2.stderr
Normal file
15
src/test/ui/hygiene/impl_items-2.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error[E0201]: duplicate definitions with name `foo`:
|
||||
--> $DIR/impl_items-2.rs:14:5
|
||||
|
|
||||
LL | fn foo() {}
|
||||
| ----------- item in trait
|
||||
...
|
||||
LL | fn foo() {}
|
||||
| ----------- previous definition here
|
||||
...
|
||||
LL | fn foo() {}
|
||||
| ^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0201`.
|
10
src/test/ui/macros/issue-102878.rs
Normal file
10
src/test/ui/macros/issue-102878.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
macro_rules!test{($l:expr,$_:r)=>({const:y y)}
|
||||
//~^ ERROR mismatched closing delimiter: `)`
|
||||
//~| ERROR invalid fragment specifier `r`
|
||||
//~| ERROR expected identifier, found keyword `const`
|
||||
//~| ERROR expected identifier, found keyword `const`
|
||||
//~| ERROR expected identifier, found `:`
|
||||
|
||||
fn s(){test!(1,i)}
|
||||
|
||||
fn main() {}
|
60
src/test/ui/macros/issue-102878.stderr
Normal file
60
src/test/ui/macros/issue-102878.stderr
Normal file
|
@ -0,0 +1,60 @@
|
|||
error: mismatched closing delimiter: `)`
|
||||
--> $DIR/issue-102878.rs:1:35
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
|
||||
| -^ ^ mismatched closing delimiter
|
||||
| ||
|
||||
| |unclosed delimiter
|
||||
| closing delimiter possibly meant for this
|
||||
|
||||
error: invalid fragment specifier `r`
|
||||
--> $DIR/issue-102878.rs:1:27
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
|
||||
| ^^^^
|
||||
|
|
||||
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
|
||||
|
||||
error: expected identifier, found keyword `const`
|
||||
--> $DIR/issue-102878.rs:1:36
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
...
|
||||
LL | fn s(){test!(1,i)}
|
||||
| ---------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: escape `const` to use it as an identifier
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)}
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `const`
|
||||
--> $DIR/issue-102878.rs:1:36
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
|
||||
| ^^^^^ expected identifier, found keyword
|
||||
...
|
||||
LL | fn s(){test!(1,i)}
|
||||
| ---------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: escape `const` to use it as an identifier
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)}
|
||||
| ++
|
||||
|
||||
error: expected identifier, found `:`
|
||||
--> $DIR/issue-102878.rs:1:41
|
||||
|
|
||||
LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
|
||||
| ^ expected identifier
|
||||
...
|
||||
LL | fn s(){test!(1,i)}
|
||||
| ---------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
error[E0201]: duplicate definitions with name `bar`:
|
||||
--> $DIR/issue-8153.rs:11:5
|
||||
|
|
||||
LL | fn bar(&self) -> isize;
|
||||
| ----------------------- item in trait
|
||||
...
|
||||
LL | fn bar(&self) -> isize {1}
|
||||
| ---------------------- previous definition of `bar` here
|
||||
| -------------------------- previous definition here
|
||||
LL | fn bar(&self) -> isize {2}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(rustc_private)]
|
||||
#![feature(map_first_last)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(never_type)]
|
||||
#![feature(try_blocks)]
|
||||
|
|
|
@ -863,7 +863,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lsp-server"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"log",
|
||||
|
@ -1502,18 +1502,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.143"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
|
||||
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.143"
|
||||
version = "1.0.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
|
||||
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1522,9 +1522,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.83"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
|
||||
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
|
@ -2082,18 +2082,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
|
|||
|
||||
[[package]]
|
||||
name = "xflags"
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
|
||||
checksum = "cbf19f5031a1a812e96fede16f8161218883079946cea87619d3613db1efd268"
|
||||
dependencies = [
|
||||
"xflags-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xflags-macros"
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
|
||||
checksum = "2afbd7f2039bb6cad2dd45f0c5dff49c0d4e26118398768b7a605524d4251809"
|
||||
|
||||
[[package]]
|
||||
name = "xshell"
|
||||
|
|
|
@ -196,7 +196,7 @@ impl ChangeFixture {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
} else {
|
||||
for (from, to, prelude) in crate_deps {
|
||||
|
@ -270,7 +270,7 @@ impl ChangeFixture {
|
|||
Env::default(),
|
||||
Ok(proc_macro),
|
||||
true,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
|
||||
for krate in all_crates {
|
||||
|
@ -398,7 +398,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
|
|||
let (version, origin) = match b.split_once(':') {
|
||||
Some(("CratesIo", data)) => match data.split_once(',') {
|
||||
Some((version, url)) => {
|
||||
(version, CrateOrigin::CratesIo { repo: Some(url.to_owned()) })
|
||||
(version, CrateOrigin::CratesIo { repo: Some(url.to_owned()), name: None })
|
||||
}
|
||||
_ => panic!("Bad crates.io parameter: {}", data),
|
||||
},
|
||||
|
@ -409,7 +409,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
|
|||
let crate_origin = match &*crate_str {
|
||||
"std" => CrateOrigin::Lang(LangCrateOrigin::Std),
|
||||
"core" => CrateOrigin::Lang(LangCrateOrigin::Core),
|
||||
_ => CrateOrigin::CratesIo { repo: None },
|
||||
_ => CrateOrigin::CratesIo { repo: None, name: None },
|
||||
};
|
||||
(crate_str, crate_origin, None)
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ impl ops::Deref for CrateName {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum CrateOrigin {
|
||||
/// Crates that are from crates.io official registry,
|
||||
CratesIo { repo: Option<String> },
|
||||
CratesIo { repo: Option<String>, name: Option<String> },
|
||||
/// Crates that are provided by the language, like std, core, proc-macro, ...
|
||||
Lang(LangCrateOrigin),
|
||||
}
|
||||
|
@ -648,7 +648,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
|
@ -660,7 +660,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
let crate3 = graph.add_crate_root(
|
||||
FileId(3u32),
|
||||
|
@ -672,7 +672,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||
|
@ -698,7 +698,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
|
@ -710,7 +710,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||
|
@ -733,7 +733,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
|
@ -745,7 +745,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
let crate3 = graph.add_crate_root(
|
||||
FileId(3u32),
|
||||
|
@ -757,7 +757,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||
|
@ -780,7 +780,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
|
@ -792,7 +792,7 @@ mod tests {
|
|||
Env::default(),
|
||||
Ok(Vec::new()),
|
||||
false,
|
||||
CrateOrigin::CratesIo { repo: None },
|
||||
CrateOrigin::CratesIo { repo: None, name: None },
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(
|
||||
|
|
|
@ -169,13 +169,17 @@ impl FlycheckActor {
|
|||
}
|
||||
fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
|
||||
let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
|
||||
if let Ok(msg) = inbox.try_recv() {
|
||||
// give restarts a preference so check outputs don't block a restart or stop
|
||||
return Some(Event::Restart(msg));
|
||||
}
|
||||
select! {
|
||||
recv(inbox) -> msg => msg.ok().map(Event::Restart),
|
||||
recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
|
||||
}
|
||||
}
|
||||
fn run(mut self, inbox: Receiver<Restart>) {
|
||||
while let Some(event) = self.next_event(&inbox) {
|
||||
'event: while let Some(event) = self.next_event(&inbox) {
|
||||
match event {
|
||||
Event::Restart(Restart::No) => {
|
||||
self.cancel_check_process();
|
||||
|
@ -183,7 +187,12 @@ impl FlycheckActor {
|
|||
Event::Restart(Restart::Yes) => {
|
||||
// Cancel the previously spawned process
|
||||
self.cancel_check_process();
|
||||
while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
|
||||
while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
|
||||
// restart chained with a stop, so just cancel
|
||||
if let Restart::No = restart {
|
||||
continue 'event;
|
||||
}
|
||||
}
|
||||
|
||||
let command = self.check_command();
|
||||
tracing::debug!(?command, "will restart flycheck");
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
//! Defines hir-level representation of structs, enums and unions
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{num::NonZeroU32, sync::Arc};
|
||||
|
||||
use base_db::CrateId;
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
name::{AsName, Name},
|
||||
InFile,
|
||||
HirFileId, InFile,
|
||||
};
|
||||
use la_arena::{Arena, ArenaMap};
|
||||
use syntax::ast::{self, HasName, HasVisibility};
|
||||
|
@ -14,15 +14,18 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
|
|||
|
||||
use crate::{
|
||||
body::{CfgExpander, LowerCtx},
|
||||
builtin_type::{BuiltinInt, BuiltinUint},
|
||||
db::DefDatabase,
|
||||
intern::Interned,
|
||||
item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
|
||||
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
|
||||
nameres::diagnostics::DefDiagnostic,
|
||||
src::HasChildSource,
|
||||
src::HasSource,
|
||||
trace::Trace,
|
||||
type_ref::TypeRef,
|
||||
visibility::RawVisibility,
|
||||
EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
|
||||
EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
|
||||
VariantId,
|
||||
};
|
||||
use cfg::CfgOptions;
|
||||
|
||||
|
@ -31,7 +34,7 @@ use cfg::CfgOptions;
|
|||
pub struct StructData {
|
||||
pub name: Name,
|
||||
pub variant_data: Arc<VariantData>,
|
||||
pub repr: Option<ReprKind>,
|
||||
pub repr: Option<ReprData>,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
|
@ -39,6 +42,7 @@ pub struct StructData {
|
|||
pub struct EnumData {
|
||||
pub name: Name,
|
||||
pub variants: Arena<EnumVariantData>,
|
||||
pub repr: Option<ReprData>,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
|
@ -63,10 +67,19 @@ pub struct FieldData {
|
|||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ReprKind {
|
||||
Packed,
|
||||
Other,
|
||||
C,
|
||||
BuiltinInt { builtin: Either<BuiltinInt, BuiltinUint>, is_c: bool },
|
||||
Transparent,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ReprData {
|
||||
pub kind: ReprKind,
|
||||
pub packed: bool,
|
||||
pub align: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
fn repr_from_value(
|
||||
|
@ -74,25 +87,71 @@ fn repr_from_value(
|
|||
krate: CrateId,
|
||||
item_tree: &ItemTree,
|
||||
of: AttrOwner,
|
||||
) -> Option<ReprKind> {
|
||||
) -> Option<ReprData> {
|
||||
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
|
||||
}
|
||||
|
||||
fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
|
||||
fn parse_repr_tt(tt: &Subtree) -> Option<ReprData> {
|
||||
match tt.delimiter {
|
||||
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
let mut it = tt.token_trees.iter();
|
||||
match it.next()? {
|
||||
TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed),
|
||||
_ => Some(ReprKind::Other),
|
||||
let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None };
|
||||
|
||||
let mut tts = tt.token_trees.iter().peekable();
|
||||
while let Some(tt) = tts.next() {
|
||||
if let TokenTree::Leaf(Leaf::Ident(ident)) = tt {
|
||||
match &*ident.text {
|
||||
"packed" => {
|
||||
data.packed = true;
|
||||
if let Some(TokenTree::Subtree(_)) = tts.peek() {
|
||||
tts.next();
|
||||
}
|
||||
}
|
||||
"align" => {
|
||||
if let Some(TokenTree::Subtree(tt)) = tts.peek() {
|
||||
tts.next();
|
||||
if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
|
||||
if let Ok(align) = lit.text.parse() {
|
||||
data.align = Some(align);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"C" => {
|
||||
if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind {
|
||||
*is_c = true;
|
||||
} else {
|
||||
data.kind = ReprKind::C;
|
||||
}
|
||||
}
|
||||
"transparent" => data.kind = ReprKind::Transparent,
|
||||
repr => {
|
||||
let is_c = matches!(data.kind, ReprKind::C);
|
||||
if let Some(builtin) = BuiltinInt::from_suffix(repr)
|
||||
.map(Either::Left)
|
||||
.or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right))
|
||||
{
|
||||
data.kind = ReprKind::BuiltinInt { builtin, is_c };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(data)
|
||||
}
|
||||
|
||||
impl StructData {
|
||||
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
|
||||
db.struct_data_with_diagnostics(id).0
|
||||
}
|
||||
|
||||
pub(crate) fn struct_data_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
id: StructId,
|
||||
) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
@ -100,15 +159,35 @@ impl StructData {
|
|||
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
|
||||
|
||||
let strukt = &item_tree[loc.id.value];
|
||||
let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
|
||||
Arc::new(StructData {
|
||||
name: strukt.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
repr,
|
||||
visibility: item_tree[strukt.visibility].clone(),
|
||||
})
|
||||
let (variant_data, diagnostics) = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.id.file_id(),
|
||||
loc.container.local_id,
|
||||
&item_tree,
|
||||
&cfg_options,
|
||||
&strukt.fields,
|
||||
None,
|
||||
);
|
||||
(
|
||||
Arc::new(StructData {
|
||||
name: strukt.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
repr,
|
||||
visibility: item_tree[strukt.visibility].clone(),
|
||||
}),
|
||||
diagnostics.into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
|
||||
db.union_data_with_diagnostics(id).0
|
||||
}
|
||||
|
||||
pub(crate) fn union_data_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
id: UnionId,
|
||||
) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
|
||||
let loc = id.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
|
@ -116,56 +195,98 @@ impl StructData {
|
|||
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
|
||||
|
||||
let union = &item_tree[loc.id.value];
|
||||
let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
|
||||
|
||||
Arc::new(StructData {
|
||||
name: union.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
repr,
|
||||
visibility: item_tree[union.visibility].clone(),
|
||||
})
|
||||
let (variant_data, diagnostics) = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.id.file_id(),
|
||||
loc.container.local_id,
|
||||
&item_tree,
|
||||
&cfg_options,
|
||||
&union.fields,
|
||||
None,
|
||||
);
|
||||
(
|
||||
Arc::new(StructData {
|
||||
name: union.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
repr,
|
||||
visibility: item_tree[union.visibility].clone(),
|
||||
}),
|
||||
diagnostics.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumData {
|
||||
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
||||
db.enum_data_with_diagnostics(e).0
|
||||
}
|
||||
|
||||
pub(crate) fn enum_data_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
e: EnumId,
|
||||
) -> (Arc<EnumData>, Arc<[DefDiagnostic]>) {
|
||||
let loc = e.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
|
||||
let enum_ = &item_tree[loc.id.value];
|
||||
let mut variants = Arena::new();
|
||||
let mut diagnostics = Vec::new();
|
||||
for tree_id in enum_.variants.clone() {
|
||||
if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) {
|
||||
let var = &item_tree[tree_id];
|
||||
let var_data = lower_fields(
|
||||
let attrs = item_tree.attrs(db, krate, tree_id.into());
|
||||
let var = &item_tree[tree_id];
|
||||
if attrs.is_cfg_enabled(&cfg_options) {
|
||||
let (var_data, field_diagnostics) = lower_fields(
|
||||
db,
|
||||
krate,
|
||||
loc.id.file_id(),
|
||||
loc.container.local_id,
|
||||
&item_tree,
|
||||
&cfg_options,
|
||||
&var.fields,
|
||||
Some(enum_.visibility),
|
||||
);
|
||||
diagnostics.extend(field_diagnostics);
|
||||
|
||||
variants.alloc(EnumVariantData {
|
||||
name: var.name.clone(),
|
||||
variant_data: Arc::new(var_data),
|
||||
});
|
||||
} else {
|
||||
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
loc.container.local_id,
|
||||
InFile::new(loc.id.file_id(), var.ast_id.upcast()),
|
||||
attrs.cfg().unwrap(),
|
||||
cfg_options.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(EnumData {
|
||||
name: enum_.name.clone(),
|
||||
variants,
|
||||
visibility: item_tree[enum_.visibility].clone(),
|
||||
})
|
||||
(
|
||||
Arc::new(EnumData {
|
||||
name: enum_.name.clone(),
|
||||
variants,
|
||||
repr,
|
||||
visibility: item_tree[enum_.visibility].clone(),
|
||||
}),
|
||||
diagnostics.into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
|
||||
let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
|
||||
Some(id)
|
||||
}
|
||||
|
||||
pub fn variant_body_type(&self) -> Either<BuiltinInt, BuiltinUint> {
|
||||
match self.repr {
|
||||
Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
|
||||
_ => Either::Left(BuiltinInt::Isize),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasChildSource<LocalEnumVariantId> for EnumId {
|
||||
|
@ -324,31 +445,64 @@ fn lower_struct(
|
|||
fn lower_fields(
|
||||
db: &dyn DefDatabase,
|
||||
krate: CrateId,
|
||||
current_file_id: HirFileId,
|
||||
container: LocalModuleId,
|
||||
item_tree: &ItemTree,
|
||||
cfg_options: &CfgOptions,
|
||||
fields: &Fields,
|
||||
override_visibility: Option<RawVisibilityId>,
|
||||
) -> VariantData {
|
||||
) -> (VariantData, Vec<DefDiagnostic>) {
|
||||
let mut diagnostics = Vec::new();
|
||||
match fields {
|
||||
Fields::Record(flds) => {
|
||||
let mut arena = Arena::new();
|
||||
for field_id in flds.clone() {
|
||||
if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
|
||||
let attrs = item_tree.attrs(db, krate, field_id.into());
|
||||
let field = &item_tree[field_id];
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, field, override_visibility));
|
||||
} else {
|
||||
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
container,
|
||||
InFile::new(
|
||||
current_file_id,
|
||||
match field.ast_id {
|
||||
FieldAstId::Record(it) => it.upcast(),
|
||||
FieldAstId::Tuple(it) => it.upcast(),
|
||||
},
|
||||
),
|
||||
attrs.cfg().unwrap(),
|
||||
cfg_options.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
VariantData::Record(arena)
|
||||
(VariantData::Record(arena), diagnostics)
|
||||
}
|
||||
Fields::Tuple(flds) => {
|
||||
let mut arena = Arena::new();
|
||||
for field_id in flds.clone() {
|
||||
if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
|
||||
let attrs = item_tree.attrs(db, krate, field_id.into());
|
||||
let field = &item_tree[field_id];
|
||||
if attrs.is_cfg_enabled(cfg_options) {
|
||||
arena.alloc(lower_field(item_tree, field, override_visibility));
|
||||
} else {
|
||||
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
container,
|
||||
InFile::new(
|
||||
current_file_id,
|
||||
match field.ast_id {
|
||||
FieldAstId::Record(it) => it.upcast(),
|
||||
FieldAstId::Tuple(it) => it.upcast(),
|
||||
},
|
||||
),
|
||||
attrs.cfg().unwrap(),
|
||||
cfg_options.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
VariantData::Tuple(arena)
|
||||
(VariantData::Tuple(arena), diagnostics)
|
||||
}
|
||||
Fields::Unit => VariantData::Unit,
|
||||
Fields::Unit => (VariantData::Unit, diagnostics),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ use crate::{
|
|||
macro_id_to_def_id,
|
||||
nameres::DefMap,
|
||||
path::{ModPath, Path},
|
||||
src::HasSource,
|
||||
src::{HasChildSource, HasSource},
|
||||
AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
|
||||
UnresolvedMacro,
|
||||
};
|
||||
|
@ -324,6 +324,12 @@ impl Body {
|
|||
let src = s.source(db);
|
||||
(src.file_id, s.module(db), src.value.body())
|
||||
}
|
||||
DefWithBodyId::VariantId(v) => {
|
||||
let e = v.parent.lookup(db);
|
||||
let src = v.parent.child_source(db);
|
||||
let variant = &src.value[v.local_id];
|
||||
(src.file_id, e.container, variant.expr())
|
||||
}
|
||||
};
|
||||
let expander = Expander::new(db, file_id, module);
|
||||
let (mut body, source_map) = Body::new(db, expander, params, body);
|
||||
|
|
|
@ -29,8 +29,9 @@ use crate::{
|
|||
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
|
||||
db::DefDatabase,
|
||||
expr::{
|
||||
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
|
||||
Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
||||
dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper,
|
||||
Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField,
|
||||
Statement,
|
||||
},
|
||||
intern::Interned,
|
||||
item_scope::BuiltinShadowMode,
|
||||
|
@ -97,6 +98,7 @@ pub(super) fn lower(
|
|||
name_to_pat_grouping: Default::default(),
|
||||
is_lowering_inside_or_pat: false,
|
||||
is_lowering_assignee_expr: false,
|
||||
is_lowering_generator: false,
|
||||
}
|
||||
.collect(params, body)
|
||||
}
|
||||
|
@ -111,6 +113,7 @@ struct ExprCollector<'a> {
|
|||
name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
|
||||
is_lowering_inside_or_pat: bool,
|
||||
is_lowering_assignee_expr: bool,
|
||||
is_lowering_generator: bool,
|
||||
}
|
||||
|
||||
impl ExprCollector<'_> {
|
||||
|
@ -358,6 +361,7 @@ impl ExprCollector<'_> {
|
|||
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::YieldExpr(e) => {
|
||||
self.is_lowering_generator = true;
|
||||
let expr = e.expr().map(|e| self.collect_expr(e));
|
||||
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
|
||||
}
|
||||
|
@ -459,13 +463,31 @@ impl ExprCollector<'_> {
|
|||
.ret_type()
|
||||
.and_then(|r| r.ty())
|
||||
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
||||
|
||||
let prev_is_lowering_generator = self.is_lowering_generator;
|
||||
self.is_lowering_generator = false;
|
||||
|
||||
let body = self.collect_expr_opt(e.body());
|
||||
|
||||
let closure_kind = if self.is_lowering_generator {
|
||||
let movability = if e.static_token().is_some() {
|
||||
Movability::Static
|
||||
} else {
|
||||
Movability::Movable
|
||||
};
|
||||
ClosureKind::Generator(movability)
|
||||
} else {
|
||||
ClosureKind::Closure
|
||||
};
|
||||
self.is_lowering_generator = prev_is_lowering_generator;
|
||||
|
||||
self.alloc_expr(
|
||||
Expr::Closure {
|
||||
args: args.into(),
|
||||
arg_types: arg_types.into(),
|
||||
ret_type,
|
||||
body,
|
||||
closure_kind,
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
use syntax::ast::HasName;
|
||||
|
||||
use crate::{
|
||||
expr::{Array, BindingAnnotation, Literal, Statement},
|
||||
expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
|
||||
pretty::{print_generic_args, print_path, print_type_ref},
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
@ -32,6 +34,16 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
|
|||
};
|
||||
format!("const {} = ", name)
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
needs_semi = false;
|
||||
let src = it.parent.child_source(db);
|
||||
let variant = &src.value[it.local_id];
|
||||
let name = match &variant.name() {
|
||||
Some(name) => name.to_string(),
|
||||
None => "_".to_string(),
|
||||
};
|
||||
format!("{}", name)
|
||||
}
|
||||
};
|
||||
|
||||
let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
|
||||
|
@ -350,7 +362,10 @@ impl<'a> Printer<'a> {
|
|||
self.print_expr(*index);
|
||||
w!(self, "]");
|
||||
}
|
||||
Expr::Closure { args, arg_types, ret_type, body } => {
|
||||
Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
|
||||
if let ClosureKind::Generator(Movability::Static) = closure_kind {
|
||||
w!(self, "static ");
|
||||
}
|
||||
w!(self, "|");
|
||||
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
|
||||
if i != 0 {
|
||||
|
|
|
@ -198,6 +198,10 @@ impl ChildBySource for EnumId {
|
|||
impl ChildBySource for DefWithBodyId {
|
||||
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
|
||||
let body = db.body(*self);
|
||||
if let &DefWithBodyId::VariantId(v) = self {
|
||||
VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id)
|
||||
}
|
||||
|
||||
for (_, def_map) in body.blocks(db) {
|
||||
// All block expressions are merged into the same map, because they logically all add
|
||||
// inner items to the containing `DefWithBodyId`.
|
||||
|
|
|
@ -219,7 +219,7 @@ impl TraitData {
|
|||
pub(crate) fn trait_data_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
tr: TraitId,
|
||||
) -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>) {
|
||||
) -> (Arc<TraitData>, Arc<[DefDiagnostic]>) {
|
||||
let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let tr_def = &item_tree[tree_id.value];
|
||||
|
@ -251,7 +251,7 @@ impl TraitData {
|
|||
visibility,
|
||||
skip_array_during_method_dispatch,
|
||||
}),
|
||||
Arc::new(diagnostics),
|
||||
diagnostics.into(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -299,7 +299,7 @@ impl ImplData {
|
|||
pub(crate) fn impl_data_with_diagnostics_query(
|
||||
db: &dyn DefDatabase,
|
||||
id: ImplId,
|
||||
) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>) {
|
||||
) -> (Arc<ImplData>, Arc<[DefDiagnostic]>) {
|
||||
let _p = profile::span("impl_data_with_diagnostics_query");
|
||||
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
|
||||
|
||||
|
@ -318,7 +318,7 @@ impl ImplData {
|
|||
|
||||
(
|
||||
Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
|
||||
Arc::new(diagnostics),
|
||||
diagnostics.into(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -97,24 +97,33 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
|
|||
#[salsa::invoke(StructData::struct_data_query)]
|
||||
fn struct_data(&self, id: StructId) -> Arc<StructData>;
|
||||
|
||||
#[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
|
||||
fn struct_data_with_diagnostics(&self, id: StructId)
|
||||
-> (Arc<StructData>, Arc<[DefDiagnostic]>);
|
||||
|
||||
#[salsa::invoke(StructData::union_data_query)]
|
||||
fn union_data(&self, id: UnionId) -> Arc<StructData>;
|
||||
|
||||
#[salsa::invoke(StructData::union_data_with_diagnostics_query)]
|
||||
fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc<StructData>, Arc<[DefDiagnostic]>);
|
||||
|
||||
#[salsa::invoke(EnumData::enum_data_query)]
|
||||
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
|
||||
|
||||
#[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
|
||||
fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc<EnumData>, Arc<[DefDiagnostic]>);
|
||||
|
||||
#[salsa::invoke(ImplData::impl_data_query)]
|
||||
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
|
||||
|
||||
#[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
|
||||
fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>);
|
||||
fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<[DefDiagnostic]>);
|
||||
|
||||
#[salsa::invoke(TraitData::trait_data_query)]
|
||||
fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
|
||||
|
||||
#[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
|
||||
fn trait_data_with_diagnostics(&self, tr: TraitId)
|
||||
-> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>);
|
||||
fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, Arc<[DefDiagnostic]>);
|
||||
|
||||
#[salsa::invoke(TypeAliasData::type_alias_data_query)]
|
||||
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
|
||||
|
|
|
@ -198,6 +198,7 @@ pub enum Expr {
|
|||
arg_types: Box<[Option<Interned<TypeRef>>]>,
|
||||
ret_type: Option<Interned<TypeRef>>,
|
||||
body: ExprId,
|
||||
closure_kind: ClosureKind,
|
||||
},
|
||||
Tuple {
|
||||
exprs: Box<[ExprId]>,
|
||||
|
@ -211,6 +212,18 @@ pub enum Expr {
|
|||
Underscore,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ClosureKind {
|
||||
Closure,
|
||||
Generator(Movability),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Movability {
|
||||
Static,
|
||||
Movable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Array {
|
||||
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
|
||||
|
|
|
@ -333,8 +333,8 @@ fn calculate_best_path(
|
|||
db,
|
||||
def_map,
|
||||
visited_modules,
|
||||
from,
|
||||
crate_root,
|
||||
from,
|
||||
info.container,
|
||||
max_len - 1,
|
||||
prefixed,
|
||||
|
|
|
@ -943,6 +943,7 @@ impl AssocItem {
|
|||
pub struct Variant {
|
||||
pub name: Name,
|
||||
pub fields: Fields,
|
||||
pub ast_id: FileAstId<ast::Variant>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -952,10 +953,17 @@ pub enum Fields {
|
|||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum FieldAstId {
|
||||
Record(FileAstId<ast::RecordField>),
|
||||
Tuple(FileAstId<ast::TupleField>),
|
||||
}
|
||||
|
||||
/// A single field of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Field {
|
||||
pub name: Name,
|
||||
pub type_ref: Interned<TypeRef>,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub ast_id: FieldAstId,
|
||||
}
|
||||
|
|
|
@ -184,7 +184,8 @@ impl<'a> Ctx<'a> {
|
|||
let name = field.name()?.as_name();
|
||||
let visibility = self.lower_visibility(field);
|
||||
let type_ref = self.lower_type_ref_opt(field.ty());
|
||||
let res = Field { name, type_ref, visibility };
|
||||
let ast_id = FieldAstId::Record(self.source_ast_id_map.ast_id(field));
|
||||
let res = Field { name, type_ref, visibility, ast_id };
|
||||
Some(res)
|
||||
}
|
||||
|
||||
|
@ -203,7 +204,8 @@ impl<'a> Ctx<'a> {
|
|||
let name = Name::new_tuple_field(idx);
|
||||
let visibility = self.lower_visibility(field);
|
||||
let type_ref = self.lower_type_ref_opt(field.ty());
|
||||
Field { name, type_ref, visibility }
|
||||
let ast_id = FieldAstId::Tuple(self.source_ast_id_map.ast_id(field));
|
||||
Field { name, type_ref, visibility, ast_id }
|
||||
}
|
||||
|
||||
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
|
||||
|
@ -247,7 +249,8 @@ impl<'a> Ctx<'a> {
|
|||
fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
|
||||
let name = variant.name()?.as_name();
|
||||
let fields = self.lower_fields(&variant.kind());
|
||||
let res = Variant { name, fields };
|
||||
let ast_id = self.source_ast_id_map.ast_id(variant);
|
||||
let res = Variant { name, fields, ast_id };
|
||||
Some(res)
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ impl<'a> Printer<'a> {
|
|||
w!(self, "{{");
|
||||
self.indented(|this| {
|
||||
for field in fields.clone() {
|
||||
let Field { visibility, name, type_ref } = &this.tree[field];
|
||||
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||
this.print_attrs_of(field);
|
||||
this.print_visibility(*visibility);
|
||||
w!(this, "{}: ", name);
|
||||
|
@ -129,7 +129,7 @@ impl<'a> Printer<'a> {
|
|||
w!(self, "(");
|
||||
self.indented(|this| {
|
||||
for field in fields.clone() {
|
||||
let Field { visibility, name, type_ref } = &this.tree[field];
|
||||
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||
this.print_attrs_of(field);
|
||||
this.print_visibility(*visibility);
|
||||
w!(this, "{}: ", name);
|
||||
|
@ -323,7 +323,7 @@ impl<'a> Printer<'a> {
|
|||
self.print_where_clause_and_opening_brace(generic_params);
|
||||
self.indented(|this| {
|
||||
for variant in variants.clone() {
|
||||
let Variant { name, fields } = &this.tree[variant];
|
||||
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
|
||||
this.print_attrs_of(variant);
|
||||
w!(this, "{}", name);
|
||||
this.print_fields(fields);
|
||||
|
|
|
@ -474,16 +474,24 @@ pub enum DefWithBodyId {
|
|||
FunctionId(FunctionId),
|
||||
StaticId(StaticId),
|
||||
ConstId(ConstId),
|
||||
VariantId(EnumVariantId),
|
||||
}
|
||||
|
||||
impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
|
||||
|
||||
impl From<EnumVariantId> for DefWithBodyId {
|
||||
fn from(id: EnumVariantId) -> Self {
|
||||
DefWithBodyId::VariantId(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl DefWithBodyId {
|
||||
pub fn as_generic_def_id(self) -> Option<GenericDefId> {
|
||||
match self {
|
||||
DefWithBodyId::FunctionId(f) => Some(f.into()),
|
||||
DefWithBodyId::StaticId(_) => None,
|
||||
DefWithBodyId::ConstId(c) => Some(c.into()),
|
||||
DefWithBodyId::VariantId(c) => Some(c.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -681,6 +689,7 @@ impl HasModule for DefWithBodyId {
|
|||
DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
|
||||
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
|
||||
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
|
||||
DefWithBodyId::VariantId(it) => it.parent.lookup(db).container,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -691,6 +700,7 @@ impl DefWithBodyId {
|
|||
DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
|
||||
DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
|
||||
DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
|
||||
DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2122,7 +2122,7 @@ impl ModCollector<'_, '_> {
|
|||
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
|
||||
let ast_id = item.ast_id(self.item_tree);
|
||||
|
||||
let ast_id = InFile::new(self.file_id(), ast_id);
|
||||
let ast_id = InFile::new(self.file_id(), ast_id.upcast());
|
||||
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||
self.module_id,
|
||||
ast_id,
|
||||
|
|
|
@ -4,7 +4,7 @@ use base_db::CrateId;
|
|||
use cfg::{CfgExpr, CfgOptions};
|
||||
use hir_expand::MacroCallKind;
|
||||
use la_arena::Idx;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{self, AnyHasAttrs};
|
||||
|
||||
use crate::{
|
||||
attr::AttrId,
|
||||
|
@ -22,7 +22,7 @@ pub enum DefDiagnosticKind {
|
|||
|
||||
UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
|
||||
|
||||
UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
|
||||
UnconfiguredCode { ast: AstId<AnyHasAttrs>, cfg: CfgExpr, opts: CfgOptions },
|
||||
|
||||
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
|
||||
|
||||
|
@ -75,7 +75,7 @@ impl DefDiagnostic {
|
|||
|
||||
pub fn unconfigured_code(
|
||||
container: LocalModuleId,
|
||||
ast: AstId<ast::Item>,
|
||||
ast: AstId<ast::AnyHasAttrs>,
|
||||
cfg: CfgExpr,
|
||||
opts: CfgOptions,
|
||||
) -> Self {
|
||||
|
|
|
@ -839,6 +839,7 @@ impl HasResolver for DefWithBodyId {
|
|||
DefWithBodyId::ConstId(c) => c.resolver(db),
|
||||
DefWithBodyId::FunctionId(f) => f.resolver(db),
|
||||
DefWithBodyId::StaticId(s) => s.resolver(db),
|
||||
DefWithBodyId::VariantId(v) => v.parent.resolver(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,12 @@ impl AstIdMap {
|
|||
// trait does not change ids of top-level items, which helps caching.
|
||||
bdfs(node, |it| {
|
||||
let kind = it.kind();
|
||||
if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
|
||||
if ast::Item::can_cast(kind)
|
||||
|| ast::BlockExpr::can_cast(kind)
|
||||
|| ast::Variant::can_cast(kind)
|
||||
|| ast::RecordField::can_cast(kind)
|
||||
|| ast::TupleField::can_cast(kind)
|
||||
{
|
||||
res.alloc(&it);
|
||||
true
|
||||
} else {
|
||||
|
|
|
@ -811,6 +811,31 @@ impl<'a> InFile<&'a SyntaxNode> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
|
||||
// This kind of upmapping can only be achieved in attribute expanded files,
|
||||
// as we don't have node inputs otherwise and therefor can't find an `N` node in the input
|
||||
if !self.file_id.is_macro() {
|
||||
return Some(self.map(Clone::clone));
|
||||
} else if !self.file_id.is_attr_macro(db) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(InFile { file_id, value: (first, last) }) = ascend_node_border_tokens(db, self)
|
||||
{
|
||||
if file_id.is_macro() {
|
||||
let range = first.text_range().cover(last.text_range());
|
||||
tracing::error!("Failed mapping out of macro file for {:?}", range);
|
||||
return None;
|
||||
}
|
||||
// FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
|
||||
let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
|
||||
let kind = self.value.kind();
|
||||
let value = anc.ancestors().find(|it| it.kind() == kind)?;
|
||||
return Some(InFile::new(file_id, value));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl InFile<SyntaxToken> {
|
||||
|
|
|
@ -263,6 +263,7 @@ pub mod known {
|
|||
Iterator,
|
||||
IntoIterator,
|
||||
Item,
|
||||
IntoIter,
|
||||
Try,
|
||||
Ok,
|
||||
Future,
|
||||
|
|
|
@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
|
|||
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(db, target);
|
||||
let b = TyBuilder::subst_for_def(db, deref_trait, None);
|
||||
if b.remaining() != 1 {
|
||||
// the Target type + Deref trait should only have one generic parameter,
|
||||
// namely Deref's Self type
|
||||
return None;
|
||||
}
|
||||
b.push(ty).build()
|
||||
let deref_subst = b.push(ty).build();
|
||||
TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
|
||||
};
|
||||
|
||||
// Check that the type implements Deref at all
|
||||
|
|
|
@ -6,19 +6,19 @@ use chalk_ir::{
|
|||
cast::{Cast, CastTo, Caster},
|
||||
fold::TypeFoldable,
|
||||
interner::HasInterner,
|
||||
AdtId, BoundVar, DebruijnIndex, Scalar,
|
||||
AdtId, DebruijnIndex, Scalar,
|
||||
};
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
|
||||
TypeAliasId,
|
||||
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
|
||||
GenericDefId, TraitId, TypeAliasId,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{
|
||||
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
|
||||
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
|
||||
ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
|
||||
TyDefId, TyExt, TyKind, ValueTyDefId,
|
||||
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
|
||||
GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
|
||||
ValueTyDefId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -34,17 +34,32 @@ pub struct TyBuilder<D> {
|
|||
data: D,
|
||||
vec: SmallVec<[GenericArg; 2]>,
|
||||
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||
parent_subst: Substitution,
|
||||
}
|
||||
|
||||
impl<A> TyBuilder<A> {
|
||||
fn with_data<B>(self, data: B) -> TyBuilder<B> {
|
||||
TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
|
||||
TyBuilder {
|
||||
data,
|
||||
vec: self.vec,
|
||||
param_kinds: self.param_kinds,
|
||||
parent_subst: self.parent_subst,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> TyBuilder<D> {
|
||||
fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
|
||||
TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
|
||||
fn new(
|
||||
data: D,
|
||||
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> Self {
|
||||
let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||
Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
|
||||
}
|
||||
|
||||
fn new_empty(data: D) -> Self {
|
||||
TyBuilder::new(data, SmallVec::new(), None)
|
||||
}
|
||||
|
||||
fn build_internal(self) -> (D, Substitution) {
|
||||
|
@ -52,13 +67,18 @@ impl<D> TyBuilder<D> {
|
|||
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
|
||||
self.assert_match_kind(a, e);
|
||||
}
|
||||
let subst = Substitution::from_iter(Interner, self.vec);
|
||||
let subst = Substitution::from_iter(
|
||||
Interner,
|
||||
self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
|
||||
);
|
||||
(self.data, subst)
|
||||
}
|
||||
|
||||
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
|
||||
assert!(self.remaining() > 0);
|
||||
let arg = arg.cast(Interner);
|
||||
let expected_kind = &self.param_kinds[self.vec.len()];
|
||||
|
||||
let arg_kind = match arg.data(Interner) {
|
||||
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
|
||||
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
|
||||
|
@ -68,7 +88,9 @@ impl<D> TyBuilder<D> {
|
|||
}
|
||||
};
|
||||
assert_eq!(*expected_kind, arg_kind);
|
||||
|
||||
self.vec.push(arg);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -79,20 +101,12 @@ impl<D> TyBuilder<D> {
|
|||
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let other = this.param_kinds.iter().skip(this.vec.len());
|
||||
let other = &this.param_kinds[this.vec.len()..];
|
||||
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
|
||||
.intern(Interner)
|
||||
ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => {
|
||||
BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
||||
ty: ty.clone(),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
});
|
||||
this.vec.extend(filler.take(this.remaining()).casted(Interner));
|
||||
assert_eq!(this.remaining(), 0);
|
||||
|
@ -102,8 +116,8 @@ impl<D> TyBuilder<D> {
|
|||
pub fn fill_with_unknown(self) -> Self {
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
|
||||
ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
|
||||
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
|
||||
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||
});
|
||||
this.vec.extend(filler.casted(Interner));
|
||||
|
@ -113,33 +127,17 @@ impl<D> TyBuilder<D> {
|
|||
|
||||
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
|
||||
self.fill(|x| match x {
|
||||
ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
|
||||
ParamKind::Const(ty) => {
|
||||
GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
|
||||
}
|
||||
ParamKind::Type => table.new_type_var().cast(Interner),
|
||||
ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
|
||||
self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
|
||||
self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
|
||||
assert_eq!(self.remaining(), 0);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
|
||||
assert!(self.vec.is_empty());
|
||||
assert!(parent_substs.len(Interner) <= self.param_kinds.len());
|
||||
self.extend(parent_substs.iter(Interner).cloned());
|
||||
self
|
||||
}
|
||||
|
||||
fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
|
||||
for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
|
||||
self.assert_match_kind(&x.0, &x.1);
|
||||
}
|
||||
self.vec.extend(it);
|
||||
}
|
||||
|
||||
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
|
||||
match (a.data(Interner), e) {
|
||||
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
|
||||
|
@ -188,21 +186,42 @@ impl TyBuilder<()> {
|
|||
params.placeholder_subst(db)
|
||||
}
|
||||
|
||||
pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
|
||||
let def = def.into();
|
||||
let params = generics(db.upcast(), def);
|
||||
TyBuilder::new(
|
||||
(),
|
||||
params
|
||||
.iter()
|
||||
.map(|(id, data)| match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
pub fn subst_for_def(
|
||||
db: &dyn HirDatabase,
|
||||
def: impl Into<GenericDefId>,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<()> {
|
||||
let generics = generics(db.upcast(), def.into());
|
||||
assert!(generics.parent_generics().is_some() == parent_subst.is_some());
|
||||
let params = generics
|
||||
.iter_self()
|
||||
.map(|(id, data)| match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
TyBuilder::new((), params, parent_subst)
|
||||
}
|
||||
|
||||
/// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
|
||||
///
|
||||
/// A generator's substitution consists of:
|
||||
/// - resume type of generator
|
||||
/// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
|
||||
/// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
|
||||
/// - generic parameters in scope on `parent`
|
||||
/// in this order.
|
||||
///
|
||||
/// This method prepopulates the builder with placeholder substitution of `parent`, so you
|
||||
/// should only push exactly 3 `GenericArg`s before building.
|
||||
pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
|
||||
let parent_subst =
|
||||
parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
|
||||
// These represent resume type, yield type, and return type of generator.
|
||||
let params = std::iter::repeat(ParamKind::Type).take(3).collect();
|
||||
TyBuilder::new((), params, parent_subst)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Substitution {
|
||||
|
@ -213,7 +232,7 @@ impl TyBuilder<()> {
|
|||
|
||||
impl TyBuilder<hir_def::AdtId> {
|
||||
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
TyBuilder::subst_for_def(db, def, None).with_data(def)
|
||||
}
|
||||
|
||||
pub fn fill_with_defaults(
|
||||
|
@ -221,16 +240,27 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
db: &dyn HirDatabase,
|
||||
mut fallback: impl FnMut() -> Ty,
|
||||
) -> Self {
|
||||
// Note that we're building ADT, so we never have parent generic parameters.
|
||||
let defaults = db.generic_defaults(self.data.into());
|
||||
let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
|
||||
for default_ty in defaults.iter().skip(self.vec.len()) {
|
||||
if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
|
||||
// NOTE(skip_binders): we only check if the arg type is error type.
|
||||
if let Some(x) = default_ty.skip_binders().ty(Interner) {
|
||||
if x.is_unknown() {
|
||||
self.vec.push(fallback().cast(Interner));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// each default can depend on the previous parameters
|
||||
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
|
||||
}
|
||||
// Each default can only depend on the previous parameters.
|
||||
// FIXME: we don't handle const generics here.
|
||||
let subst_so_far = Substitution::from_iter(
|
||||
Interner,
|
||||
self.vec
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(iter::repeat(dummy_ty.clone()))
|
||||
.take(self.param_kinds.len()),
|
||||
);
|
||||
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
|
||||
}
|
||||
self
|
||||
|
@ -245,7 +275,7 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
pub struct Tuple(usize);
|
||||
impl TyBuilder<Tuple> {
|
||||
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
|
||||
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
|
||||
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Ty {
|
||||
|
@ -256,7 +286,7 @@ impl TyBuilder<Tuple> {
|
|||
|
||||
impl TyBuilder<TraitId> {
|
||||
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
TyBuilder::subst_for_def(db, def, None).with_data(def)
|
||||
}
|
||||
|
||||
pub fn build(self) -> TraitRef {
|
||||
|
@ -266,8 +296,12 @@ impl TyBuilder<TraitId> {
|
|||
}
|
||||
|
||||
impl TyBuilder<TypeAliasId> {
|
||||
pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
pub fn assoc_type_projection(
|
||||
db: &dyn HirDatabase,
|
||||
def: TypeAliasId,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<TypeAliasId> {
|
||||
TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
|
||||
}
|
||||
|
||||
pub fn build(self) -> ProjectionTy {
|
||||
|
@ -277,19 +311,6 @@ impl TyBuilder<TypeAliasId> {
|
|||
}
|
||||
|
||||
impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
|
||||
fn subst_binders(b: Binders<T>) -> Self {
|
||||
let param_kinds = b
|
||||
.binders
|
||||
.iter(Interner)
|
||||
.map(|x| match x {
|
||||
chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
|
||||
chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
|
||||
chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
|
||||
})
|
||||
.collect();
|
||||
TyBuilder::new(b, param_kinds)
|
||||
}
|
||||
|
||||
pub fn build(self) -> T {
|
||||
let (b, subst) = self.build_internal();
|
||||
b.substitute(Interner, &subst)
|
||||
|
@ -297,15 +318,41 @@ impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Bin
|
|||
}
|
||||
|
||||
impl TyBuilder<Binders<Ty>> {
|
||||
pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
|
||||
TyBuilder::subst_binders(db.ty(def))
|
||||
pub fn def_ty(
|
||||
db: &dyn HirDatabase,
|
||||
def: TyDefId,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<Binders<Ty>> {
|
||||
let poly_ty = db.ty(def);
|
||||
let id: GenericDefId = match def {
|
||||
TyDefId::BuiltinType(_) => {
|
||||
assert!(parent_subst.is_none());
|
||||
return TyBuilder::new_empty(poly_ty);
|
||||
}
|
||||
TyDefId::AdtId(id) => id.into(),
|
||||
TyDefId::TypeAliasId(id) => id.into(),
|
||||
};
|
||||
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
|
||||
}
|
||||
|
||||
pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
|
||||
TyBuilder::subst_binders(db.impl_self_ty(def))
|
||||
TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
|
||||
}
|
||||
|
||||
pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
|
||||
TyBuilder::subst_binders(db.value_ty(def))
|
||||
pub fn value_ty(
|
||||
db: &dyn HirDatabase,
|
||||
def: ValueTyDefId,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<Binders<Ty>> {
|
||||
let poly_value_ty = db.value_ty(def);
|
||||
let id = match def.to_generic_def_id() {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
// static items
|
||||
assert!(parent_subst.is_none());
|
||||
return TyBuilder::new_empty(poly_value_ty);
|
||||
}
|
||||
};
|
||||
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
|
|||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
expr::Movability,
|
||||
lang_item::{lang_attr, LangItemTarget},
|
||||
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
|
||||
};
|
||||
|
@ -26,9 +27,9 @@ use crate::{
|
|||
to_assoc_type_id, to_chalk_trait_id,
|
||||
traits::ChalkContext,
|
||||
utils::generics,
|
||||
AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
|
||||
ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
|
||||
TyExt, TyKind, WhereClause,
|
||||
wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
|
||||
Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
|
||||
TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
|
||||
|
@ -372,17 +373,62 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
}
|
||||
fn generator_datum(
|
||||
&self,
|
||||
_: chalk_ir::GeneratorId<Interner>,
|
||||
id: chalk_ir::GeneratorId<Interner>,
|
||||
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
|
||||
// FIXME
|
||||
unimplemented!()
|
||||
let (parent, expr) = self.db.lookup_intern_generator(id.into());
|
||||
|
||||
// We fill substitution with unknown type, because we only need to know whether the generic
|
||||
// params are types or consts to build `Binders` and those being filled up are for
|
||||
// `resume_type`, `yield_type`, and `return_type` of the generator in question.
|
||||
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||
|
||||
let input_output = rust_ir::GeneratorInputOutputDatum {
|
||||
resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
|
||||
.intern(Interner),
|
||||
yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
|
||||
.intern(Interner),
|
||||
return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
|
||||
.intern(Interner),
|
||||
// FIXME: calculate upvars
|
||||
upvars: vec![],
|
||||
};
|
||||
|
||||
let it = subst
|
||||
.iter(Interner)
|
||||
.map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
|
||||
let input_output = crate::make_type_and_const_binders(it, input_output);
|
||||
|
||||
let movability = match self.db.body(parent)[expr] {
|
||||
hir_def::expr::Expr::Closure {
|
||||
closure_kind: hir_def::expr::ClosureKind::Generator(movability),
|
||||
..
|
||||
} => movability,
|
||||
_ => unreachable!("non generator expression interned as generator"),
|
||||
};
|
||||
let movability = match movability {
|
||||
Movability::Static => rust_ir::Movability::Static,
|
||||
Movability::Movable => rust_ir::Movability::Movable,
|
||||
};
|
||||
|
||||
Arc::new(rust_ir::GeneratorDatum { movability, input_output })
|
||||
}
|
||||
fn generator_witness_datum(
|
||||
&self,
|
||||
_: chalk_ir::GeneratorId<Interner>,
|
||||
id: chalk_ir::GeneratorId<Interner>,
|
||||
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
|
||||
// FIXME
|
||||
unimplemented!()
|
||||
// FIXME: calculate inner types
|
||||
let inner_types =
|
||||
rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) };
|
||||
|
||||
let (parent, _) = self.db.lookup_intern_generator(id.into());
|
||||
// See the comment in `generator_datum()` for unknown types.
|
||||
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||
let it = subst
|
||||
.iter(Interner)
|
||||
.map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
|
||||
let inner_types = crate::make_type_and_const_binders(it, inner_types);
|
||||
|
||||
Arc::new(rust_ir::GeneratorWitnessDatum { inner_types })
|
||||
}
|
||||
|
||||
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
|
||||
|
@ -429,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
|
|||
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
||||
let ctx = crate::TyLoweringContext::new(db, &resolver)
|
||||
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
|
||||
|
||||
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
|
||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
|
||||
.build();
|
||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
|
||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
|
||||
.build();
|
||||
let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
|
||||
|
||||
let mut bounds: Vec<_> = type_alias_data
|
||||
.bounds
|
||||
.iter()
|
||||
|
|
|
@ -152,7 +152,7 @@ impl TyExt for Ty {
|
|||
TyKind::FnDef(def, parameters) => {
|
||||
let callable_def = db.lookup_intern_callable_def((*def).into());
|
||||
let sig = db.callable_item_signature(callable_def);
|
||||
Some(sig.substitute(Interner, ¶meters))
|
||||
Some(sig.substitute(Interner, parameters))
|
||||
}
|
||||
TyKind::Closure(.., substs) => {
|
||||
let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
|
||||
|
@ -166,6 +166,8 @@ impl TyExt for Ty {
|
|||
let trait_ref = match self.kind(Interner) {
|
||||
// The principal trait bound should be the first element of the bounds. This is an
|
||||
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
|
||||
// FIXME: dyn types may not have principal trait and we don't want to return auto trait
|
||||
// here.
|
||||
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
|
||||
match b.skip_binders() {
|
||||
WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
||||
|
|
|
@ -7,14 +7,17 @@ use std::{
|
|||
|
||||
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinInt,
|
||||
expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId},
|
||||
path::ModPath,
|
||||
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
|
||||
src::HasChildSource,
|
||||
type_ref::ConstScalar,
|
||||
ConstId, DefWithBodyId,
|
||||
ConstId, DefWithBodyId, EnumVariantId, Lookup,
|
||||
};
|
||||
use la_arena::{Arena, Idx};
|
||||
use la_arena::{Arena, Idx, RawIdx};
|
||||
use stdx::never;
|
||||
use syntax::ast::HasName;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
|
||||
|
@ -77,6 +80,7 @@ pub enum ConstEvalError {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ComputedExpr {
|
||||
Literal(Literal),
|
||||
Enum(String, EnumVariantId, Literal),
|
||||
Tuple(Box<[ComputedExpr]>),
|
||||
}
|
||||
|
||||
|
@ -104,6 +108,7 @@ impl Display for ComputedExpr {
|
|||
Literal::String(x) => std::fmt::Debug::fmt(x, f),
|
||||
Literal::ByteString(x) => std::fmt::Debug::fmt(x, f),
|
||||
},
|
||||
ComputedExpr::Enum(name, _, _) => name.fmt(f),
|
||||
ComputedExpr::Tuple(t) => {
|
||||
f.write_char('(')?;
|
||||
for x in &**t {
|
||||
|
@ -148,13 +153,51 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_name(ctx: &mut ConstEvalCtx<'_>, variant: EnumVariantId) -> String {
|
||||
let loc = variant.parent.lookup(ctx.db.upcast());
|
||||
let children = variant.parent.child_source(ctx.db.upcast());
|
||||
let item_tree = loc.id.item_tree(ctx.db.upcast());
|
||||
|
||||
let variant_name = children.value[variant.local_id].name();
|
||||
let enum_name = item_tree[loc.id.value].name.to_string();
|
||||
enum_name + "::" + &variant_name.unwrap().to_string()
|
||||
}
|
||||
|
||||
pub fn eval_const(
|
||||
expr_id: ExprId,
|
||||
ctx: &mut ConstEvalCtx<'_>,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let u128_to_i128 = |it: u128| -> Result<i128, ConstEvalError> {
|
||||
it.try_into().map_err(|_| ConstEvalError::NotSupported("u128 is too big"))
|
||||
};
|
||||
|
||||
let expr = &ctx.exprs[expr_id];
|
||||
match expr {
|
||||
Expr::Missing => Err(ConstEvalError::IncompleteExpr),
|
||||
Expr::Missing => match ctx.owner {
|
||||
// evaluate the implicit variant index of an enum variant without expression
|
||||
// FIXME: This should return the type of the enum representation
|
||||
DefWithBodyId::VariantId(variant) => {
|
||||
let prev_idx: u32 = variant.local_id.into_raw().into();
|
||||
let prev_idx = prev_idx.checked_sub(1).map(RawIdx::from).map(Idx::from_raw);
|
||||
let value = match prev_idx {
|
||||
Some(local_id) => {
|
||||
let prev_variant = EnumVariantId { local_id, parent: variant.parent };
|
||||
1 + match ctx.db.const_eval_variant(prev_variant)? {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => {
|
||||
return Err(ConstEvalError::NotSupported(
|
||||
"Enum can't contain this kind of value",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
Ok(ComputedExpr::Literal(Literal::Int(value, Some(BuiltinInt::I128))))
|
||||
}
|
||||
_ => Err(ConstEvalError::IncompleteExpr),
|
||||
},
|
||||
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
||||
&Expr::UnaryOp { expr, op } => {
|
||||
let ty = &ctx.expr_ty(expr);
|
||||
|
@ -167,9 +210,7 @@ pub fn eval_const(
|
|||
return Ok(ComputedExpr::Literal(Literal::Bool(!b)))
|
||||
}
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => v
|
||||
.try_into()
|
||||
.map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
let r = match ty.kind(Interner) {
|
||||
|
@ -198,9 +239,7 @@ pub fn eval_const(
|
|||
hir_def::expr::UnaryOp::Neg => {
|
||||
let v = match ev {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => v
|
||||
.try_into()
|
||||
.map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
Ok(ComputedExpr::Literal(Literal::Int(
|
||||
|
@ -219,16 +258,12 @@ pub fn eval_const(
|
|||
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
|
||||
let v1 = match lhs {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => {
|
||||
v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
|
||||
}
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
let v2 = match rhs {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => {
|
||||
v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
|
||||
}
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
match op {
|
||||
|
@ -339,9 +374,22 @@ pub fn eval_const(
|
|||
ValueNs::GenericParam(_) => {
|
||||
Err(ConstEvalError::NotSupported("const generic without substitution"))
|
||||
}
|
||||
ValueNs::EnumVariantId(id) => match ctx.db.const_eval_variant(id)? {
|
||||
ComputedExpr::Literal(lit) => {
|
||||
Ok(ComputedExpr::Enum(get_name(ctx, id), id, lit))
|
||||
}
|
||||
_ => Err(ConstEvalError::NotSupported(
|
||||
"Enums can't evalute to anything but numbers",
|
||||
)),
|
||||
},
|
||||
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
|
||||
}
|
||||
}
|
||||
// FIXME: Handle the cast target
|
||||
&Expr::Cast { expr, .. } => match eval_const(expr, ctx)? {
|
||||
ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)),
|
||||
_ => Err(ConstEvalError::NotSupported("Can't cast these types")),
|
||||
},
|
||||
_ => Err(ConstEvalError::NotSupported("This kind of expression")),
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +460,15 @@ pub(crate) fn const_eval_recover(
|
|||
Err(ConstEvalError::Loop)
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_query(
|
||||
pub(crate) fn const_eval_variant_recover(
|
||||
_: &dyn HirDatabase,
|
||||
_: &[String],
|
||||
_: &EnumVariantId,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
Err(ConstEvalError::Loop)
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_variant_query(
|
||||
db: &dyn HirDatabase,
|
||||
const_id: ConstId,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
|
@ -433,6 +489,26 @@ pub(crate) fn const_eval_query(
|
|||
result
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_query_variant(
|
||||
db: &dyn HirDatabase,
|
||||
variant_id: EnumVariantId,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let def = variant_id.into();
|
||||
let body = db.body(def);
|
||||
let infer = &db.infer(def);
|
||||
eval_const(
|
||||
body.body_expr,
|
||||
&mut ConstEvalCtx {
|
||||
db,
|
||||
owner: def,
|
||||
exprs: &body.exprs,
|
||||
pats: &body.pats,
|
||||
local_data: HashMap::default(),
|
||||
infer,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn eval_to_const<'a>(
|
||||
expr: Idx<Expr>,
|
||||
mode: ParamLoweringMode,
|
||||
|
|
|
@ -87,6 +87,49 @@ fn consts() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enums() {
|
||||
check_number(
|
||||
r#"
|
||||
enum E {
|
||||
F1 = 1,
|
||||
F2 = 2 * E::F1 as u8,
|
||||
F3 = 3 * E::F2 as u8,
|
||||
}
|
||||
const GOAL: i32 = E::F3 as u8;
|
||||
"#,
|
||||
6,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
enum E { F1 = 1, F2, }
|
||||
const GOAL: i32 = E::F2 as u8;
|
||||
"#,
|
||||
2,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
enum E { F1, }
|
||||
const GOAL: i32 = E::F1 as u8;
|
||||
"#,
|
||||
0,
|
||||
);
|
||||
let r = eval_goal(
|
||||
r#"
|
||||
enum E { A = 1, }
|
||||
const GOAL: E = E::A;
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
match r {
|
||||
ComputedExpr::Enum(name, _, Literal::Uint(val, _)) => {
|
||||
assert_eq!(name, "E::A");
|
||||
assert_eq!(val, 1);
|
||||
}
|
||||
x => panic!("Expected enum but found {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_loop() {
|
||||
check_fail(
|
||||
|
|
|
@ -6,8 +6,8 @@ use std::sync::Arc;
|
|||
use arrayvec::ArrayVec;
|
||||
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
|
||||
use hir_def::{
|
||||
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
|
||||
GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
||||
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
|
||||
FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
||||
};
|
||||
use la_arena::ArenaMap;
|
||||
|
||||
|
@ -43,10 +43,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
||||
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||
#[salsa::invoke(crate::consteval::const_eval_variant_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||
fn const_eval(&self, def: ConstId) -> Result<ComputedExpr, ConstEvalError>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query_variant)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_variant_recover)]
|
||||
fn const_eval_variant(&self, def: EnumVariantId) -> Result<ComputedExpr, ConstEvalError>;
|
||||
|
||||
#[salsa::invoke(crate::lower::impl_trait_query)]
|
||||
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
||||
|
||||
|
@ -116,6 +120,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
|
||||
#[salsa::interned]
|
||||
fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
|
||||
#[salsa::interned]
|
||||
fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId;
|
||||
|
||||
#[salsa::invoke(chalk_db::associated_ty_data_query)]
|
||||
fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
|
||||
|
@ -188,6 +194,9 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
|
|||
DefWithBodyId::ConstId(it) => {
|
||||
db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
db.enum_data(it.parent).variants[it.local_id].name.to_string()
|
||||
}
|
||||
});
|
||||
db.infer_query(def)
|
||||
}
|
||||
|
@ -226,6 +235,10 @@ impl_intern_key!(InternedOpaqueTyId);
|
|||
pub struct InternedClosureId(salsa::InternId);
|
||||
impl_intern_key!(InternedClosureId);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct InternedGeneratorId(salsa::InternId);
|
||||
impl_intern_key!(InternedGeneratorId);
|
||||
|
||||
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
|
||||
/// we have different IDs for struct and enum variant constructors.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
|
|
|
@ -18,7 +18,9 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
|||
|
||||
let is_unsafe = match def {
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => {
|
||||
false
|
||||
}
|
||||
};
|
||||
if is_unsafe {
|
||||
return res;
|
||||
|
|
|
@ -20,13 +20,14 @@ use hir_def::{
|
|||
};
|
||||
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||
use itertools::Itertools;
|
||||
use smallvec::SmallVec;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
|
||||
mapping::from_chalk,
|
||||
primitive, subst_prefix, to_assoc_type_id,
|
||||
primitive, to_assoc_type_id,
|
||||
utils::{self, generics},
|
||||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
|
||||
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
|
||||
|
@ -221,6 +222,7 @@ pub enum DisplaySourceCodeError {
|
|||
PathNotFound,
|
||||
UnknownType,
|
||||
Closure,
|
||||
Generator,
|
||||
}
|
||||
|
||||
pub enum HirDisplayError {
|
||||
|
@ -504,8 +506,15 @@ impl HirDisplay for Ty {
|
|||
let total_len = parent_params + self_param + type_params + const_params;
|
||||
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
|
||||
if total_len > 0 {
|
||||
// `parameters` are in the order of fn's params (including impl traits),
|
||||
// parent's params (those from enclosing impl or trait, if any).
|
||||
let parameters = parameters.as_slice(Interner);
|
||||
let fn_params_len = self_param + type_params + const_params;
|
||||
let fn_params = parameters.get(..fn_params_len);
|
||||
let parent_params = parameters.get(parameters.len() - parent_params..);
|
||||
let params = parent_params.into_iter().chain(fn_params).flatten();
|
||||
write!(f, "<")?;
|
||||
f.write_joined(¶meters.as_slice(Interner)[..total_len], ", ")?;
|
||||
f.write_joined(params, ", ")?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
}
|
||||
|
@ -577,9 +586,8 @@ impl HirDisplay for Ty {
|
|||
Some(x) => x,
|
||||
None => return true,
|
||||
};
|
||||
let actual_default = default_parameter
|
||||
.clone()
|
||||
.substitute(Interner, &subst_prefix(parameters, i));
|
||||
let actual_default =
|
||||
default_parameter.clone().substitute(Interner, ¶meters);
|
||||
parameter != &actual_default
|
||||
}
|
||||
let mut default_from = 0;
|
||||
|
@ -783,7 +791,34 @@ impl HirDisplay for Ty {
|
|||
write!(f, "{{unknown}}")?;
|
||||
}
|
||||
TyKind::InferenceVar(..) => write!(f, "_")?,
|
||||
TyKind::Generator(..) => write!(f, "{{generator}}")?,
|
||||
TyKind::Generator(_, subst) => {
|
||||
if f.display_target.is_source_code() {
|
||||
return Err(HirDisplayError::DisplaySourceCodeError(
|
||||
DisplaySourceCodeError::Generator,
|
||||
));
|
||||
}
|
||||
|
||||
let subst = subst.as_slice(Interner);
|
||||
let a: Option<SmallVec<[&Ty; 3]>> = subst
|
||||
.get(subst.len() - 3..)
|
||||
.map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
|
||||
.flatten();
|
||||
|
||||
if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
|
||||
write!(f, "|")?;
|
||||
resume_ty.hir_fmt(f)?;
|
||||
write!(f, "|")?;
|
||||
|
||||
write!(f, " yields ")?;
|
||||
yield_ty.hir_fmt(f)?;
|
||||
|
||||
write!(f, " -> ")?;
|
||||
ret_ty.hir_fmt(f)?;
|
||||
} else {
|
||||
// This *should* be unreachable, but fallback just in case.
|
||||
write!(f, "{{generator}}")?;
|
||||
}
|
||||
}
|
||||
TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -19,14 +19,15 @@ use std::sync::Arc;
|
|||
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
builtin_type::BuiltinType,
|
||||
data::{ConstData, StaticData},
|
||||
expr::{BindingAnnotation, ExprId, PatId},
|
||||
lang_item::LangItemTarget,
|
||||
path::{path, Path},
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
type_ref::TypeRef,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
|
||||
TraitId, TypeAliasId, VariantId,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
|
||||
ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use itertools::Either;
|
||||
|
@ -67,6 +68,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
|||
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
||||
DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
|
||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
||||
DefWithBodyId::VariantId(v) => {
|
||||
ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
|
||||
Either::Left(builtin) => BuiltinType::Int(builtin),
|
||||
Either::Right(builtin) => BuiltinType::Uint(builtin),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ctx.infer_body();
|
||||
|
@ -332,7 +339,7 @@ pub struct InferenceResult {
|
|||
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
||||
pub type_of_pat: ArenaMap<PatId, Ty>,
|
||||
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||
/// Interned Unknown to return references to.
|
||||
/// Interned common types to return references to.
|
||||
standard_types: InternedStandardTypes,
|
||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
||||
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
||||
|
@ -412,6 +419,8 @@ pub(crate) struct InferenceContext<'a> {
|
|||
/// closures, but currently this is the only field that will change there,
|
||||
/// so it doesn't make sense.
|
||||
return_ty: Ty,
|
||||
/// The resume type and the yield type, respectively, of the generator being inferred.
|
||||
resume_yield_tys: Option<(Ty, Ty)>,
|
||||
diverges: Diverges,
|
||||
breakables: Vec<BreakableContext>,
|
||||
}
|
||||
|
@ -476,6 +485,7 @@ impl<'a> InferenceContext<'a> {
|
|||
table: unify::InferenceTable::new(db, trait_env.clone()),
|
||||
trait_env,
|
||||
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
|
||||
resume_yield_tys: None,
|
||||
db,
|
||||
owner,
|
||||
body,
|
||||
|
@ -703,6 +713,8 @@ impl<'a> InferenceContext<'a> {
|
|||
&mut self,
|
||||
inner_ty: Ty,
|
||||
assoc_ty: Option<TypeAliasId>,
|
||||
// FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
|
||||
// handled when we support them.
|
||||
params: &[GenericArg],
|
||||
) -> Ty {
|
||||
match assoc_ty {
|
||||
|
@ -794,7 +806,18 @@ impl<'a> InferenceContext<'a> {
|
|||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
}
|
||||
TypeNs::TypeAliasId(it) => {
|
||||
let ty = TyBuilder::def_ty(self.db, it.into())
|
||||
let container = it.lookup(self.db.upcast()).container;
|
||||
let parent_subst = match container {
|
||||
ItemContainerId::TraitId(id) => {
|
||||
let subst = TyBuilder::subst_for_def(self.db, id, None)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
Some(subst)
|
||||
}
|
||||
// Type aliases do not exist in impls.
|
||||
_ => None,
|
||||
};
|
||||
let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
|
@ -873,6 +896,12 @@ impl<'a> InferenceContext<'a> {
|
|||
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
||||
let path = path![core::iter::IntoIterator];
|
||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||
self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
|
||||
}
|
||||
|
||||
fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
|
||||
let path = path![core::iter::Iterator];
|
||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
use super::{Expectation, InferenceContext};
|
||||
|
||||
impl InferenceContext<'_> {
|
||||
// This function handles both closures and generators.
|
||||
pub(super) fn deduce_closure_type_from_expectations(
|
||||
&mut self,
|
||||
closure_expr: ExprId,
|
||||
|
@ -27,6 +28,11 @@ impl InferenceContext<'_> {
|
|||
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
||||
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
|
||||
|
||||
// Generators are not Fn* so return early.
|
||||
if matches!(closure_ty.kind(Interner), TyKind::Generator(..)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deduction based on the expected `dyn Fn` is done separately.
|
||||
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
|
||||
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
||||
|
|
|
@ -10,7 +10,10 @@ use chalk_ir::{
|
|||
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
|
||||
};
|
||||
use hir_def::{
|
||||
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
|
||||
expr::{
|
||||
ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
|
||||
UnaryOp,
|
||||
},
|
||||
generics::TypeOrConstParamData,
|
||||
path::{GenericArg, GenericArgs},
|
||||
resolver::resolver_for_expr,
|
||||
|
@ -204,8 +207,10 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
&Expr::For { iterable, body, pat, label } => {
|
||||
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
|
||||
let pat_ty =
|
||||
let into_iter_ty =
|
||||
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
||||
let pat_ty =
|
||||
self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
|
||||
|
||||
self.infer_pat(pat, &pat_ty, BindingMode::default());
|
||||
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
|
||||
|
@ -216,7 +221,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.diverges = Diverges::Maybe;
|
||||
TyBuilder::unit()
|
||||
}
|
||||
Expr::Closure { body, args, ret_type, arg_types } => {
|
||||
Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
|
||||
assert_eq!(args.len(), arg_types.len());
|
||||
|
||||
let mut sig_tys = Vec::new();
|
||||
|
@ -244,20 +249,40 @@ impl<'a> InferenceContext<'a> {
|
|||
),
|
||||
})
|
||||
.intern(Interner);
|
||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||
let closure_ty =
|
||||
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
||||
.intern(Interner);
|
||||
|
||||
let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
|
||||
// FIXME: report error when there are more than 1 parameter.
|
||||
let resume_ty = match sig_tys.first() {
|
||||
// When `sig_tys.len() == 1` the first type is the return type, not the
|
||||
// first parameter type.
|
||||
Some(ty) if sig_tys.len() > 1 => ty.clone(),
|
||||
_ => self.result.standard_types.unit.clone(),
|
||||
};
|
||||
let yield_ty = self.table.new_type_var();
|
||||
|
||||
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
|
||||
.push(resume_ty.clone())
|
||||
.push(yield_ty.clone())
|
||||
.push(ret_ty.clone())
|
||||
.build();
|
||||
|
||||
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
|
||||
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
|
||||
|
||||
(generator_ty, Some((resume_ty, yield_ty)))
|
||||
} else {
|
||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||
let closure_ty =
|
||||
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
||||
.intern(Interner);
|
||||
|
||||
(closure_ty, None)
|
||||
};
|
||||
|
||||
// Eagerly try to relate the closure type with the expected
|
||||
// type, otherwise we often won't have enough information to
|
||||
// infer the body.
|
||||
self.deduce_closure_type_from_expectations(
|
||||
tgt_expr,
|
||||
&closure_ty,
|
||||
&sig_ty,
|
||||
expected,
|
||||
);
|
||||
self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
|
||||
|
||||
// Now go through the argument patterns
|
||||
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
||||
|
@ -266,6 +291,8 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
||||
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
|
||||
let prev_resume_yield_tys =
|
||||
mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
|
||||
|
||||
self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
|
||||
this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
|
||||
|
@ -273,8 +300,9 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
self.diverges = prev_diverges;
|
||||
self.return_ty = prev_ret_ty;
|
||||
self.resume_yield_tys = prev_resume_yield_tys;
|
||||
|
||||
closure_ty
|
||||
ty
|
||||
}
|
||||
Expr::Call { callee, args, .. } => {
|
||||
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
||||
|
@ -423,11 +451,18 @@ impl<'a> InferenceContext<'a> {
|
|||
TyKind::Never.intern(Interner)
|
||||
}
|
||||
Expr::Yield { expr } => {
|
||||
// FIXME: track yield type for coercion
|
||||
if let Some(expr) = expr {
|
||||
self.infer_expr(*expr, &Expectation::none());
|
||||
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
|
||||
if let Some(expr) = expr {
|
||||
self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
|
||||
} else {
|
||||
let unit = self.result.standard_types.unit.clone();
|
||||
let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
|
||||
}
|
||||
resume_ty
|
||||
} else {
|
||||
// FIXME: report error (yield expr in non-generator)
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
TyKind::Never.intern(Interner)
|
||||
}
|
||||
Expr::RecordLit { path, fields, spread, .. } => {
|
||||
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
|
||||
|
@ -952,11 +987,13 @@ impl<'a> InferenceContext<'a> {
|
|||
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
|
||||
let rhs_ty = self.table.new_type_var();
|
||||
|
||||
let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
|
||||
let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
|
||||
let func = self.db.trait_data(trait_id).method_by_name(&name)?;
|
||||
Some((trait_id, func))
|
||||
});
|
||||
let func = match func {
|
||||
Some(func) => func,
|
||||
let (trait_, func) = match trait_func {
|
||||
Some(it) => it,
|
||||
None => {
|
||||
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
|
||||
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
|
||||
|
@ -966,7 +1003,9 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let subst = TyBuilder::subst_for_def(self.db, func)
|
||||
// HACK: We can use this substitution for the function because the function itself doesn't
|
||||
// have its own generic parameters.
|
||||
let subst = TyBuilder::subst_for_def(self.db, trait_, None)
|
||||
.push(lhs_ty.clone())
|
||||
.push(rhs_ty.clone())
|
||||
.build();
|
||||
|
@ -1245,19 +1284,7 @@ impl<'a> InferenceContext<'a> {
|
|||
assert_eq!(self_params, 0); // method shouldn't have another Self param
|
||||
let total_len = parent_params + type_params + const_params + impl_trait_params;
|
||||
let mut substs = Vec::with_capacity(total_len);
|
||||
// Parent arguments are unknown
|
||||
for (id, param) in def_generics.iter_parent() {
|
||||
match param {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
|
||||
substs
|
||||
.push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle provided arguments
|
||||
if let Some(generic_args) = generic_args {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
|
@ -1266,7 +1293,7 @@ impl<'a> InferenceContext<'a> {
|
|||
.iter()
|
||||
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
||||
.take(type_params + const_params)
|
||||
.zip(def_generics.iter_id().skip(parent_params))
|
||||
.zip(def_generics.iter_id())
|
||||
{
|
||||
if let Some(g) = generic_arg_to_chalk(
|
||||
self.db,
|
||||
|
@ -1290,6 +1317,9 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle everything else as unknown. This also handles generic arguments for the method's
|
||||
// parent (impl or trait), which should come after those for the method.
|
||||
for (id, data) in def_generics.iter().skip(substs.len()) {
|
||||
match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
|
@ -1327,9 +1357,13 @@ impl<'a> InferenceContext<'a> {
|
|||
CallableDefId::FunctionId(f) => {
|
||||
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
|
||||
// construct a TraitRef
|
||||
let substs = crate::subst_prefix(
|
||||
&*parameters,
|
||||
generics(self.db.upcast(), trait_.into()).len(),
|
||||
let params_len = parameters.len(Interner);
|
||||
let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
|
||||
let substs = Substitution::from_iter(
|
||||
Interner,
|
||||
// The generic parameters for the trait come after those for the
|
||||
// function.
|
||||
¶meters.as_slice(Interner)[params_len - trait_params_len..],
|
||||
);
|
||||
self.push_obligation(
|
||||
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
|
||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
|||
builder::ParamKind,
|
||||
consteval,
|
||||
method_resolution::{self, VisibleFromModule},
|
||||
GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
|
||||
ValueTyDefId,
|
||||
utils::generics,
|
||||
Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
|
||||
};
|
||||
|
||||
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
||||
|
@ -96,17 +96,21 @@ impl<'a> InferenceContext<'a> {
|
|||
ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
|
||||
};
|
||||
|
||||
let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
||||
let substs = ctx.substs_from_path(path, typable, true);
|
||||
let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable)
|
||||
.use_parent_substs(&parent_substs)
|
||||
let substs = substs.as_slice(Interner);
|
||||
let parent_substs = self_subst.or_else(|| {
|
||||
let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
|
||||
let parent_params_len = generics.parent_generics()?.len();
|
||||
let parent_args = &substs[substs.len() - parent_params_len..];
|
||||
Some(Substitution::from_iter(Interner, parent_args))
|
||||
});
|
||||
let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
|
||||
let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
|
||||
.fill(|x| {
|
||||
it.next().unwrap_or_else(|| match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
|
||||
})
|
||||
})
|
||||
|
@ -249,7 +253,7 @@ impl<'a> InferenceContext<'a> {
|
|||
};
|
||||
let substs = match container {
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
let impl_self_ty =
|
||||
|
|
|
@ -598,11 +598,14 @@ impl<'a> InferenceTable<'a> {
|
|||
.build();
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
|
||||
let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
|
||||
if b.remaining() != 2 {
|
||||
return None;
|
||||
}
|
||||
b.push(ty.clone()).push(arg_ty).build()
|
||||
let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
|
||||
|
||||
TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
|
||||
.build()
|
||||
};
|
||||
|
||||
let trait_env = self.trait_env.env.clone();
|
||||
|
|
|
@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// FIXME we're probably doing something wrong here
|
||||
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
|
||||
let (
|
||||
parent_params,
|
||||
_parent_params,
|
||||
self_params,
|
||||
list_params,
|
||||
const_params,
|
||||
|
@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
};
|
||||
TyKind::BoundVar(BoundVar::new(
|
||||
self.in_binders,
|
||||
idx as usize + parent_params + self_params + list_params + const_params,
|
||||
idx as usize + self_params + list_params + const_params,
|
||||
))
|
||||
.intern(Interner)
|
||||
}
|
||||
|
@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
|
|||
.intern(Interner)
|
||||
}
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
let generics = generics(self.db.upcast(), impl_id.into());
|
||||
let substs = match self.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
||||
ParamLoweringMode::Variable => {
|
||||
generics.bound_vars_subst(self.db, self.in_binders)
|
||||
let def =
|
||||
self.resolver.generic_def().expect("impl should have generic param scope");
|
||||
let generics = generics(self.db.upcast(), def);
|
||||
|
||||
match self.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
// `def` can be either impl itself or item within, and we need impl itself
|
||||
// now.
|
||||
let generics = generics.parent_generics().unwrap_or(&generics);
|
||||
let subst = generics.placeholder_subst(self.db);
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
|
||||
}
|
||||
};
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
|
||||
ParamLoweringMode::Variable => {
|
||||
let starting_from = match def {
|
||||
GenericDefId::ImplId(_) => 0,
|
||||
// `def` is an item within impl. We need to substitute `BoundVar`s but
|
||||
// remember that they are for parent (i.e. impl) generic params so they
|
||||
// come after our own params.
|
||||
_ => generics.len_self(),
|
||||
};
|
||||
TyBuilder::impl_self_ty(self.db, impl_id)
|
||||
.fill_with_bound_vars(self.in_binders, starting_from)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeNs::AdtSelfType(adt) => {
|
||||
let generics = generics(self.db.upcast(), adt.into());
|
||||
|
@ -663,40 +680,31 @@ impl<'a> TyLoweringContext<'a> {
|
|||
fn substs_from_path_segment(
|
||||
&self,
|
||||
segment: PathSegment<'_>,
|
||||
def_generic: Option<GenericDefId>,
|
||||
def: Option<GenericDefId>,
|
||||
infer_args: bool,
|
||||
explicit_self_ty: Option<Ty>,
|
||||
) -> Substitution {
|
||||
// Remember that the item's own generic args come before its parent's.
|
||||
let mut substs = Vec::new();
|
||||
let def_generics = if let Some(def) = def_generic {
|
||||
generics(self.db.upcast(), def)
|
||||
let def = if let Some(d) = def {
|
||||
d
|
||||
} else {
|
||||
return Substitution::empty(Interner);
|
||||
};
|
||||
let def_generics = generics(self.db.upcast(), def);
|
||||
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
|
||||
def_generics.provenance_split();
|
||||
let total_len =
|
||||
parent_params + self_params + type_params + const_params + impl_trait_params;
|
||||
let item_len = self_params + type_params + const_params + impl_trait_params;
|
||||
let total_len = parent_params + item_len;
|
||||
|
||||
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
|
||||
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
|
||||
|
||||
let mut def_generic_iter = def_generics.iter_id();
|
||||
|
||||
for _ in 0..parent_params {
|
||||
if let Some(eid) = def_generic_iter.next() {
|
||||
match eid {
|
||||
Either::Left(_) => substs.push(ty_error.clone()),
|
||||
Either::Right(x) => {
|
||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fill_self_params = || {
|
||||
for x in explicit_self_ty
|
||||
.into_iter()
|
||||
.map(|x| GenericArgData::Ty(x).intern(Interner))
|
||||
.map(|x| x.cast(Interner))
|
||||
.chain(iter::repeat(ty_error.clone()))
|
||||
.take(self_params)
|
||||
{
|
||||
|
@ -757,37 +765,40 @@ impl<'a> TyLoweringContext<'a> {
|
|||
fill_self_params();
|
||||
}
|
||||
|
||||
// These params include those of parent.
|
||||
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
|
||||
.map(|eid| match eid {
|
||||
Either::Left(_) => ty_error.clone(),
|
||||
Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(remaining_params.len() + substs.len(), total_len);
|
||||
|
||||
// handle defaults. In expression or pattern path segments without
|
||||
// explicitly specified type arguments, missing type arguments are inferred
|
||||
// (i.e. defaults aren't used).
|
||||
if !infer_args || had_explicit_args {
|
||||
if let Some(def_generic) = def_generic {
|
||||
let defaults = self.db.generic_defaults(def_generic);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
let defaults = self.db.generic_defaults(def);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
let parent_from = item_len - substs.len();
|
||||
|
||||
for default_ty in defaults.iter().skip(substs.len()) {
|
||||
// each default can depend on the previous parameters
|
||||
let substs_so_far = Substitution::from_iter(Interner, substs.clone());
|
||||
if let Some(_id) = def_generic_iter.next() {
|
||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||
}
|
||||
}
|
||||
for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
|
||||
// each default can depend on the previous parameters
|
||||
let substs_so_far = Substitution::from_iter(
|
||||
Interner,
|
||||
substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
|
||||
);
|
||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||
}
|
||||
|
||||
// Keep parent's params as unknown.
|
||||
let mut remaining_params = remaining_params;
|
||||
substs.extend(remaining_params.drain(parent_from..));
|
||||
} else {
|
||||
substs.extend(remaining_params);
|
||||
}
|
||||
|
||||
// add placeholders for args that were not provided
|
||||
// FIXME: emit diagnostics in contexts where this is not allowed
|
||||
for eid in def_generic_iter {
|
||||
match eid {
|
||||
Either::Left(_) => substs.push(ty_error.clone()),
|
||||
Either::Right(x) => {
|
||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
|
||||
assert_eq!(substs.len(), total_len);
|
||||
|
||||
Substitution::from_iter(Interner, substs)
|
||||
}
|
||||
|
||||
|
@ -981,10 +992,11 @@ impl<'a> TyLoweringContext<'a> {
|
|||
|
||||
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||
// INVARIANT: The principal trait bound must come first. Others may be in any order but
|
||||
// should be in the same order for the same set but possibly different order of bounds in
|
||||
// the input.
|
||||
// This invariant is used by `TyExt::dyn_trait()` and chalk.
|
||||
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
|
||||
// order but should be in the same order for the same set but possibly different order of
|
||||
// bounds in the input.
|
||||
// INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
|
||||
// These invariants are utilized by `TyExt::dyn_trait()` and chalk.
|
||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||
let mut bounds: Vec<_> = bounds
|
||||
.iter()
|
||||
|
@ -1035,6 +1047,12 @@ impl<'a> TyLoweringContext<'a> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if bounds.first().and_then(|b| b.trait_id()).is_none() {
|
||||
// When there's no trait bound, that's an error. This happens when the trait refs
|
||||
// are unresolved.
|
||||
return None;
|
||||
}
|
||||
|
||||
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
|
||||
// bounds. We shouldn't have repeated elements besides auto traits at this point.
|
||||
bounds.dedup();
|
||||
|
@ -1046,7 +1064,8 @@ impl<'a> TyLoweringContext<'a> {
|
|||
let bounds = crate::make_single_type_binders(bounds);
|
||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||
} else {
|
||||
// FIXME: report error (additional non-auto traits or associated type rebound)
|
||||
// FIXME: report error
|
||||
// (additional non-auto traits, associated type rebound, or no resolved trait)
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
}
|
||||
|
@ -1139,11 +1158,28 @@ fn named_associated_type_shorthand_candidates<R>(
|
|||
};
|
||||
|
||||
match res {
|
||||
TypeNs::SelfType(impl_id) => search(
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
// we're _in_ the impl -- the binders get added back later. Correct,
|
||||
// but it would be nice to make this more explicit
|
||||
db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
|
||||
),
|
||||
let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
|
||||
|
||||
let impl_id_as_generic_def: GenericDefId = impl_id.into();
|
||||
if impl_id_as_generic_def != def {
|
||||
// `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
|
||||
// `BoundVar`s from `def`'s point of view.
|
||||
// FIXME: A `HirDatabase` query may be handy if this process is needed in more
|
||||
// places. It'd be almost identical as `impl_trait_query` where `resolver` would be
|
||||
// of `def` instead of `impl_id`.
|
||||
let starting_idx = generics(db.upcast(), def).len_self();
|
||||
let subst = TyBuilder::subst_for_def(db, impl_id, None)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||
.build();
|
||||
let trait_ref = subst.apply(trait_ref, Interner);
|
||||
search(trait_ref)
|
||||
} else {
|
||||
search(trait_ref)
|
||||
}
|
||||
}
|
||||
TypeNs::GenericParam(param_id) => {
|
||||
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
|
||||
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
|
||||
|
@ -1160,10 +1196,18 @@ fn named_associated_type_shorthand_candidates<R>(
|
|||
}
|
||||
// Handle `Self::Type` referring to own associated type in trait definitions
|
||||
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
|
||||
let generics = generics(db.upcast(), trait_id.into());
|
||||
if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let trait_generics = generics(db.upcast(), trait_id.into());
|
||||
if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let def_generics = generics(db.upcast(), def);
|
||||
let starting_idx = match def {
|
||||
GenericDefId::TraitId(_) => 0,
|
||||
// `def` is an item within trait. We need to substitute `BoundVar`s but
|
||||
// remember that they are for parent (i.e. trait) generic params so they
|
||||
// come after our own params.
|
||||
_ => def_generics.len_self(),
|
||||
};
|
||||
let trait_ref = TyBuilder::trait_ref(db, trait_id)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||
.build();
|
||||
return search(trait_ref);
|
||||
}
|
||||
|
@ -1405,6 +1449,7 @@ pub(crate) fn generic_defaults_query(
|
|||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let generic_params = generics(db.upcast(), def);
|
||||
let parent_start_idx = generic_params.len_self();
|
||||
|
||||
let defaults = generic_params
|
||||
.iter()
|
||||
|
@ -1417,19 +1462,17 @@ pub(crate) fn generic_defaults_query(
|
|||
let val = unknown_const_as_generic(
|
||||
db.const_param_ty(ConstParamId::from_unchecked(id)),
|
||||
);
|
||||
return crate::make_binders_with_count(db, idx, &generic_params, val);
|
||||
return make_binders(db, &generic_params, val);
|
||||
}
|
||||
};
|
||||
let mut ty =
|
||||
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
|
||||
|
||||
// Each default can only refer to previous parameters.
|
||||
// type variable default referring to parameter coming
|
||||
// after it. This is forbidden (FIXME: report
|
||||
// diagnostic)
|
||||
ty = fallback_bound_vars(ty, idx);
|
||||
let val = GenericArgData::Ty(ty).intern(Interner);
|
||||
crate::make_binders_with_count(db, idx, &generic_params, val)
|
||||
// Type variable default referring to parameter coming
|
||||
// after it is forbidden (FIXME: report diagnostic)
|
||||
ty = fallback_bound_vars(ty, idx, parent_start_idx);
|
||||
crate::make_binders(db, &generic_params, ty.cast(Interner))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1446,15 +1489,14 @@ pub(crate) fn generic_defaults_recover(
|
|||
// we still need one default per parameter
|
||||
let defaults = generic_params
|
||||
.iter_id()
|
||||
.enumerate()
|
||||
.map(|(count, id)| {
|
||||
.map(|id| {
|
||||
let val = match id {
|
||||
itertools::Either::Left(_) => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
|
||||
};
|
||||
crate::make_binders_with_count(db, count, &generic_params, val)
|
||||
crate::make_binders(db, &generic_params, val)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1633,6 +1675,19 @@ pub enum ValueTyDefId {
|
|||
}
|
||||
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
|
||||
|
||||
impl ValueTyDefId {
|
||||
pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
|
||||
match self {
|
||||
Self::FunctionId(id) => Some(id.into()),
|
||||
Self::StructId(id) => Some(id.into()),
|
||||
Self::UnionId(id) => Some(id.into()),
|
||||
Self::EnumVariantId(var) => Some(var.into()),
|
||||
Self::ConstId(id) => Some(id.into()),
|
||||
Self::StaticId(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the declared type of an item. This depends on the namespace; e.g. for
|
||||
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
|
||||
/// the constructor function `(usize) -> Foo` which lives in the values
|
||||
|
@ -1816,26 +1871,48 @@ pub(crate) fn const_or_path_to_chalk(
|
|||
}
|
||||
}
|
||||
|
||||
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
||||
/// num_vars_to_keep) by `TyKind::Unknown`.
|
||||
/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
|
||||
/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
|
||||
/// appears after the generic parameter of `param_index`.
|
||||
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
|
||||
s: T,
|
||||
num_vars_to_keep: usize,
|
||||
param_index: usize,
|
||||
parent_start: usize,
|
||||
) -> T {
|
||||
// Keep in mind that parent generic parameters, if any, come *after* those of the item in
|
||||
// question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
|
||||
// its parent respectively.
|
||||
let is_allowed = |index| {
|
||||
if param_index < parent_start {
|
||||
// The parameter of `param_index` is one from the item in question. Any parent generic
|
||||
// parameters or the item's generic parameters that come before `param_index` is
|
||||
// allowed.
|
||||
// [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
|
||||
// ^^^^^^ ^^^^^^^^^^ these are allowed
|
||||
!(param_index..parent_start).contains(&index)
|
||||
} else {
|
||||
// The parameter of `param_index` is one from the parent generics. Only parent generic
|
||||
// parameters that come before `param_index` are allowed.
|
||||
// [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
|
||||
// ^^^^^^ these are allowed
|
||||
(parent_start..param_index).contains(&index)
|
||||
}
|
||||
};
|
||||
|
||||
crate::fold_free_vars(
|
||||
s,
|
||||
|bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
TyKind::Error.intern(Interner)
|
||||
} else {
|
||||
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||
bound.shifted_in_from(binders).to_ty(Interner)
|
||||
} else {
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
},
|
||||
|ty, bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
unknown_const(ty.clone())
|
||||
} else {
|
||||
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||
bound.shifted_in_from(binders).to_const(Interner, ty)
|
||||
} else {
|
||||
unknown_const(ty.clone())
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -103,6 +103,18 @@ impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<chalk_ir::GeneratorId<Interner>> for crate::db::InternedGeneratorId {
|
||||
fn from(id: chalk_ir::GeneratorId<Interner>) -> Self {
|
||||
Self::from_intern_id(id.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::db::InternedGeneratorId> for chalk_ir::GeneratorId<Interner> {
|
||||
fn from(id: crate::db::InternedGeneratorId) -> Self {
|
||||
chalk_ir::GeneratorId(id.as_intern_id())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
|
||||
chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
|
||||
}
|
||||
|
|
|
@ -654,7 +654,7 @@ fn find_matching_impl(
|
|||
let r = table.run_in_snapshot(|table| {
|
||||
let impl_data = db.impl_data(impl_);
|
||||
let substs =
|
||||
TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
|
||||
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
|
||||
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
|
||||
|
||||
table
|
||||
|
@ -1147,10 +1147,9 @@ fn is_valid_candidate(
|
|||
}));
|
||||
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);
|
||||
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
table.unify(&expected_self_ty, &self_ty)
|
||||
});
|
||||
if !self_ty_matches {
|
||||
|
@ -1186,31 +1185,26 @@ fn is_valid_fn_candidate(
|
|||
|
||||
table.run_in_snapshot(|table| {
|
||||
let container = fn_id.lookup(db.upcast()).container;
|
||||
let impl_subst = match container {
|
||||
let (impl_subst, expect_self_ty) = match container {
|
||||
ItemContainerId::ImplId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||
let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
|
||||
(subst, self_ty)
|
||||
}
|
||||
ItemContainerId::TraitId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||
let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
|
||||
(subst, self_ty)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id)
|
||||
.use_parent_substs(&impl_subst)
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
|
||||
let expect_self_ty = match container {
|
||||
ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
fn_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!()
|
||||
}
|
||||
};
|
||||
check_that!(table.unify(&expect_self_ty, self_ty));
|
||||
|
||||
if let Some(receiver_ty) = receiver_ty {
|
||||
|
|
|
@ -16,7 +16,7 @@ use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
|
|||
use expect_test::Expect;
|
||||
use hir_def::{
|
||||
body::{Body, BodySourceMap, SyntheticSyntax},
|
||||
db::DefDatabase,
|
||||
db::{DefDatabase, InternDatabase},
|
||||
expr::{ExprId, PatId},
|
||||
item_scope::ItemScope,
|
||||
nameres::DefMap,
|
||||
|
@ -135,6 +135,10 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
|
|||
let loc = it.lookup(&db);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = db.lookup_intern_enum(it.parent);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
});
|
||||
let mut unexpected_type_mismatches = String::new();
|
||||
for def in defs {
|
||||
|
@ -388,6 +392,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
|||
let loc = it.lookup(&db);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = db.lookup_intern_enum(it.parent);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
});
|
||||
for def in defs {
|
||||
let (_body, source_map) = db.body_with_source_map(def);
|
||||
|
@ -453,6 +461,18 @@ fn visit_module(
|
|||
let body = db.body(def);
|
||||
visit_body(db, &body, cb);
|
||||
}
|
||||
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
||||
db.enum_data(it)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
|
||||
.for_each(|it| {
|
||||
let def = it.into();
|
||||
cb(def);
|
||||
let body = db.body(def);
|
||||
visit_body(db, &body, cb);
|
||||
});
|
||||
}
|
||||
ModuleDefId::TraitId(it) => {
|
||||
let trait_data = db.trait_data(it);
|
||||
for &(_, item) in trait_data.items.iter() {
|
||||
|
|
|
@ -294,6 +294,24 @@ fn foo() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator_yield_return_coerce() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
fn test() {
|
||||
let g = || {
|
||||
yield &1u32;
|
||||
yield &&1u32;
|
||||
if true {
|
||||
return &1u32;
|
||||
}
|
||||
&&1u32
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_coerce() {
|
||||
check_no_mismatches(
|
||||
|
|
|
@ -1488,7 +1488,6 @@ fn regression_11688_4() {
|
|||
|
||||
#[test]
|
||||
fn gat_crash_1() {
|
||||
cov_mark::check!(ignore_gats);
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait ATrait {}
|
||||
|
@ -1527,30 +1526,22 @@ unsafe impl Storage for InlineStorage {
|
|||
|
||||
#[test]
|
||||
fn gat_crash_3() {
|
||||
// FIXME: This test currently crashes rust analyzer in a debug build but not in a
|
||||
// release build (i.e. for the user). With the assumption that tests will always be run
|
||||
// in debug mode, we catch the unwind and expect that it panicked. See the
|
||||
// [`crate::utils::generics`] function for more information.
|
||||
cov_mark::check!(ignore_gats);
|
||||
std::panic::catch_unwind(|| {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait Collection {
|
||||
type Item;
|
||||
type Member<T>: Collection<Item = T>;
|
||||
fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
|
||||
type Item;
|
||||
type Member<T>: Collection<Item = T>;
|
||||
fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
|
||||
}
|
||||
struct ConstGen<T, const N: usize> {
|
||||
data: [T; N],
|
||||
data: [T; N],
|
||||
}
|
||||
impl<T, const N: usize> Collection for ConstGen<T, N> {
|
||||
type Item = T;
|
||||
type Member<U> = ConstGen<U, N>;
|
||||
type Item = T;
|
||||
type Member<U> = ConstGen<U, N>;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
})
|
||||
.expect_err("must panic");
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1691,3 +1682,28 @@ fn macrostmts() -> u8 {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dyn_with_unresolved_trait() {
|
||||
check_types(
|
||||
r#"
|
||||
fn foo(a: &dyn DoesNotExist) {
|
||||
a.bar();
|
||||
//^&{unknown}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn self_assoc_with_const_generics_crash() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait Trait { type Item; }
|
||||
impl<T, const N: usize> Trait for [T; N] {
|
||||
type Item = ();
|
||||
fn f<U>(_: Self::Item) {}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1693,16 +1693,16 @@ fn infer_type_param() {
|
|||
fn infer_const() {
|
||||
check_infer(
|
||||
r#"
|
||||
struct Foo;
|
||||
impl Foo { const ASSOC_CONST: u32 = 0; }
|
||||
const GLOBAL_CONST: u32 = 101;
|
||||
fn test() {
|
||||
const LOCAL_CONST: u32 = 99;
|
||||
let x = LOCAL_CONST;
|
||||
let z = GLOBAL_CONST;
|
||||
let id = Foo::ASSOC_CONST;
|
||||
}
|
||||
"#,
|
||||
struct Foo;
|
||||
impl Foo { const ASSOC_CONST: u32 = 0; }
|
||||
const GLOBAL_CONST: u32 = 101;
|
||||
fn test() {
|
||||
const LOCAL_CONST: u32 = 99;
|
||||
let x = LOCAL_CONST;
|
||||
let z = GLOBAL_CONST;
|
||||
let id = Foo::ASSOC_CONST;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
48..49 '0': u32
|
||||
79..82 '101': u32
|
||||
|
@ -1722,17 +1722,17 @@ fn infer_const() {
|
|||
fn infer_static() {
|
||||
check_infer(
|
||||
r#"
|
||||
static GLOBAL_STATIC: u32 = 101;
|
||||
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
||||
fn test() {
|
||||
static LOCAL_STATIC: u32 = 99;
|
||||
static mut LOCAL_STATIC_MUT: u32 = 99;
|
||||
let x = LOCAL_STATIC;
|
||||
let y = LOCAL_STATIC_MUT;
|
||||
let z = GLOBAL_STATIC;
|
||||
let w = GLOBAL_STATIC_MUT;
|
||||
}
|
||||
"#,
|
||||
static GLOBAL_STATIC: u32 = 101;
|
||||
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
||||
fn test() {
|
||||
static LOCAL_STATIC: u32 = 99;
|
||||
static mut LOCAL_STATIC_MUT: u32 = 99;
|
||||
let x = LOCAL_STATIC;
|
||||
let y = LOCAL_STATIC_MUT;
|
||||
let z = GLOBAL_STATIC;
|
||||
let w = GLOBAL_STATIC_MUT;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
28..31 '101': u32
|
||||
69..72 '101': u32
|
||||
|
@ -1751,6 +1751,41 @@ fn infer_static() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_enum_variant() {
|
||||
check_infer(
|
||||
r#"
|
||||
enum Foo {
|
||||
A = 15,
|
||||
B = Foo::A as isize + 1
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
19..21 '15': isize
|
||||
31..37 'Foo::A': Foo
|
||||
31..46 'Foo::A as isize': isize
|
||||
31..50 'Foo::A...ze + 1': isize
|
||||
49..50 '1': isize
|
||||
"#]],
|
||||
);
|
||||
check_infer(
|
||||
r#"
|
||||
#[repr(u32)]
|
||||
enum Foo {
|
||||
A = 15,
|
||||
B = Foo::A as u32 + 1
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
32..34 '15': u32
|
||||
44..50 'Foo::A': Foo
|
||||
44..57 'Foo::A as u32': u32
|
||||
44..61 'Foo::A...32 + 1': u32
|
||||
60..61 '1': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowing_primitive() {
|
||||
check_types(
|
||||
|
@ -1917,6 +1952,88 @@ fn closure_return_inferred() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator_types_inferred() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: generator, deref
|
||||
use core::ops::{Generator, GeneratorState};
|
||||
use core::pin::Pin;
|
||||
|
||||
fn f(v: i64) {}
|
||||
fn test() {
|
||||
let mut g = |r| {
|
||||
let a = yield 0;
|
||||
let a = yield 1;
|
||||
let a = yield 2;
|
||||
"return value"
|
||||
};
|
||||
|
||||
match Pin::new(&mut g).resume(0usize) {
|
||||
GeneratorState::Yielded(y) => { f(y); }
|
||||
GeneratorState::Complete(r) => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
70..71 'v': i64
|
||||
78..80 '{}': ()
|
||||
91..362 '{ ... } }': ()
|
||||
101..106 'mut g': |usize| yields i64 -> &str
|
||||
109..218 '|r| { ... }': |usize| yields i64 -> &str
|
||||
110..111 'r': usize
|
||||
113..218 '{ ... }': &str
|
||||
127..128 'a': usize
|
||||
131..138 'yield 0': usize
|
||||
137..138 '0': i64
|
||||
152..153 'a': usize
|
||||
156..163 'yield 1': usize
|
||||
162..163 '1': i64
|
||||
177..178 'a': usize
|
||||
181..188 'yield 2': usize
|
||||
187..188 '2': i64
|
||||
198..212 '"return value"': &str
|
||||
225..360 'match ... }': ()
|
||||
231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
|
||||
231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
|
||||
231..262 'Pin::n...usize)': GeneratorState<i64, &str>
|
||||
240..246 '&mut g': &mut |usize| yields i64 -> &str
|
||||
245..246 'g': |usize| yields i64 -> &str
|
||||
255..261 '0usize': usize
|
||||
273..299 'Genera...ded(y)': GeneratorState<i64, &str>
|
||||
297..298 'y': i64
|
||||
303..312 '{ f(y); }': ()
|
||||
305..306 'f': fn f(i64)
|
||||
305..309 'f(y)': ()
|
||||
307..308 'y': i64
|
||||
321..348 'Genera...ete(r)': GeneratorState<i64, &str>
|
||||
346..347 'r': &str
|
||||
352..354 '{}': ()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator_resume_yield_return_unit() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: generator, deref
|
||||
use core::ops::{Generator, GeneratorState};
|
||||
use core::pin::Pin;
|
||||
fn test() {
|
||||
let mut g = || {
|
||||
let () = yield;
|
||||
};
|
||||
|
||||
match Pin::new(&mut g).resume(()) {
|
||||
GeneratorState::Yielded(()) => {}
|
||||
GeneratorState::Complete(()) => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_pointer_return() {
|
||||
check_infer(
|
||||
|
|
|
@ -279,6 +279,10 @@ fn test() {
|
|||
pub mod iter {
|
||||
pub trait IntoIterator {
|
||||
type Item;
|
||||
type IntoIter: Iterator<Item = Self::Item>;
|
||||
}
|
||||
pub trait Iterator {
|
||||
type Item;
|
||||
}
|
||||
}
|
||||
pub mod prelude {
|
||||
|
@ -297,7 +301,13 @@ pub mod collections {
|
|||
}
|
||||
|
||||
impl<T> IntoIterator for Vec<T> {
|
||||
type Item=T;
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
}
|
||||
|
||||
struct IntoIter<T> {}
|
||||
impl<T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use std::iter;
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
|
||||
use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex};
|
||||
use hir_def::{
|
||||
db::DefDatabase,
|
||||
generics::{
|
||||
|
@ -24,8 +24,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
|
||||
TraitRef, TraitRefExt, TyKind, WhereClause,
|
||||
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
|
||||
|
@ -174,31 +173,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
|
|||
|
||||
pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
|
||||
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
|
||||
if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
|
||||
let params = db.generic_params(def);
|
||||
let parent_params = &parent_generics.as_ref().unwrap().params;
|
||||
let has_consts =
|
||||
params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
||||
let parent_has_consts =
|
||||
parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
||||
return if has_consts || parent_has_consts {
|
||||
// XXX: treat const generic associated types as not existing to avoid crashes
|
||||
// (#11769)
|
||||
//
|
||||
// Note: Also crashes when the parent has const generics (also even if the GAT
|
||||
// doesn't use them), see `tests::regression::gat_crash_3` for an example.
|
||||
// Avoids that by disabling GATs when the parent (i.e. `impl` block) has
|
||||
// const generics (#12193).
|
||||
//
|
||||
// Chalk expects the inner associated type's parameters to come
|
||||
// *before*, not after the trait's generics as we've always done it.
|
||||
// Adapting to this requires a larger refactoring
|
||||
cov_mark::hit!(ignore_gats);
|
||||
Generics { def, params: Interned::new(Default::default()), parent_generics }
|
||||
} else {
|
||||
Generics { def, params, parent_generics }
|
||||
};
|
||||
}
|
||||
Generics { def, params: db.generic_params(def), parent_generics }
|
||||
}
|
||||
|
||||
|
@ -221,23 +195,30 @@ impl Generics {
|
|||
})
|
||||
}
|
||||
|
||||
/// Iterator over types and const params of parent, then self.
|
||||
/// Iterator over types and const params of self, then parent.
|
||||
pub(crate) fn iter<'a>(
|
||||
&'a self,
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
let to_toc_id = |it: &'a Generics| {
|
||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
||||
};
|
||||
self.parent_generics()
|
||||
.into_iter()
|
||||
.flat_map(move |it| it.params.iter().map(to_toc_id(it)))
|
||||
.chain(self.params.iter().map(to_toc_id(self)))
|
||||
self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
|
||||
}
|
||||
|
||||
/// Iterate over types and const params without parent params.
|
||||
pub(crate) fn iter_self<'a>(
|
||||
&'a self,
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
let to_toc_id = |it: &'a Generics| {
|
||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
||||
};
|
||||
self.params.iter().map(to_toc_id(self))
|
||||
}
|
||||
|
||||
/// Iterator over types and const params of parent.
|
||||
pub(crate) fn iter_parent<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
self.parent_generics().into_iter().flat_map(|it| {
|
||||
let to_toc_id =
|
||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
|
||||
|
@ -245,12 +226,18 @@ impl Generics {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns total number of generic parameters in scope, including those from parent.
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
let parent = self.parent_generics().map_or(0, Generics::len);
|
||||
let child = self.params.type_or_consts.len();
|
||||
parent + child
|
||||
}
|
||||
|
||||
/// Returns numbers of generic parameters excluding those from parent.
|
||||
pub(crate) fn len_self(&self) -> usize {
|
||||
self.params.type_or_consts.len()
|
||||
}
|
||||
|
||||
/// (parent total, self param, type param list, const param list, impl trait)
|
||||
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
|
||||
let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
|
||||
|
@ -275,15 +262,17 @@ impl Generics {
|
|||
if param.parent == self.def {
|
||||
let (idx, (_local_id, data)) =
|
||||
self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
|
||||
let parent_len = self.parent_generics().map_or(0, Generics::len);
|
||||
Some((parent_len + idx, data))
|
||||
Some((idx, data))
|
||||
} else {
|
||||
self.parent_generics().and_then(|g| g.find_param(param))
|
||||
self.parent_generics()
|
||||
.and_then(|g| g.find_param(param))
|
||||
// Remember that parent parameters come after parameters for self.
|
||||
.map(|(idx, data)| (self.len_self() + idx, data))
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_generics(&self) -> Option<&Generics> {
|
||||
self.parent_generics.as_ref().map(|it| &**it)
|
||||
pub(crate) fn parent_generics(&self) -> Option<&Generics> {
|
||||
self.parent_generics.as_deref()
|
||||
}
|
||||
|
||||
/// Returns a Substitution that replaces each parameter by a bound variable.
|
||||
|
@ -295,18 +284,10 @@ impl Generics {
|
|||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.iter_id().enumerate().map(|(idx, id)| match id {
|
||||
Either::Left(_) => GenericArgData::Ty(
|
||||
TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Right(id) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
||||
ty: db.const_param_ty(id),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
|
||||
Either::Right(id) => BoundVar::new(debruijn, idx)
|
||||
.to_const(Interner, db.const_param_ty(id))
|
||||
.cast(Interner),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
@ -316,18 +297,12 @@ impl Generics {
|
|||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.iter_id().map(|id| match id {
|
||||
Either::Left(id) => GenericArgData::Ty(
|
||||
TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Right(id) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
|
||||
ty: db.const_param_ty(id),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Left(id) => {
|
||||
crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
|
||||
}
|
||||
Either::Right(id) => crate::to_placeholder_idx(db, id.into())
|
||||
.to_const(Interner, db.const_param_ty(id))
|
||||
.cast(Interner),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Re-export diagnostics such that clients of `hir` don't have to depend on
|
||||
//! low-level crates.
|
||||
//!
|
||||
//! This probably isn't the best way to do this -- ideally, diagnistics should
|
||||
//! This probably isn't the best way to do this -- ideally, diagnostics should
|
||||
//! be expressed in terms of hir types themselves.
|
||||
use base_db::CrateId;
|
||||
use cfg::{CfgExpr, CfgOptions};
|
||||
|
|
|
@ -492,6 +492,9 @@ impl HirDisplay for TypeAlias {
|
|||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.type_alias_data(self.id);
|
||||
write!(f, "type {}", data.name)?;
|
||||
let def_id = GenericDefId::TypeAliasId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
if !data.bounds.is_empty() {
|
||||
f.write_str(": ")?;
|
||||
f.write_joined(&data.bounds, " + ")?;
|
||||
|
|
|
@ -140,6 +140,7 @@ impl From<DefWithBody> for DefWithBodyId {
|
|||
DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
|
||||
DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
|
||||
DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
|
||||
DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +151,7 @@ impl From<DefWithBodyId> for DefWithBody {
|
|||
DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()),
|
||||
DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()),
|
||||
DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()),
|
||||
DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,9 +174,7 @@ impl From<GenericDef> for GenericDefId {
|
|||
GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
|
||||
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
|
||||
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
|
||||
GenericDef::Variant(it) => {
|
||||
GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id })
|
||||
}
|
||||
GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()),
|
||||
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
|
||||
}
|
||||
}
|
||||
|
@ -188,9 +188,7 @@ impl From<GenericDefId> for GenericDef {
|
|||
GenericDefId::TraitId(it) => GenericDef::Trait(it.into()),
|
||||
GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
|
||||
GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
|
||||
GenericDefId::EnumVariantId(it) => {
|
||||
GenericDef::Variant(Variant { parent: it.parent.into(), id: it.local_id })
|
||||
}
|
||||
GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()),
|
||||
GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ use arrayvec::ArrayVec;
|
|||
use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
adt::{ReprKind, VariantData},
|
||||
adt::{ReprData, VariantData},
|
||||
body::{BodyDiagnostic, SyntheticSyntax},
|
||||
expr::{BindingAnnotation, LabelId, Pat, PatId},
|
||||
generics::{TypeOrConstParamData, TypeParamProvenance},
|
||||
|
@ -50,7 +50,7 @@ use hir_def::{
|
|||
resolver::{HasResolver, Resolver},
|
||||
src::HasSource as _,
|
||||
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
|
||||
FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
|
||||
EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
|
||||
LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
|
||||
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
|
||||
};
|
||||
|
@ -61,7 +61,6 @@ use hir_ty::{
|
|||
diagnostics::BodyValidationDiagnostic,
|
||||
method_resolution::{self, TyFingerprint},
|
||||
primitive::UintTy,
|
||||
subst_prefix,
|
||||
traits::FnTrait,
|
||||
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
|
||||
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
||||
|
@ -73,7 +72,7 @@ use once_cell::unsync::Lazy;
|
|||
use rustc_hash::FxHashSet;
|
||||
use stdx::{impl_from, never};
|
||||
use syntax::{
|
||||
ast::{self, HasAttrs as _, HasDocComments, HasName},
|
||||
ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
|
||||
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
|
||||
};
|
||||
|
||||
|
@ -348,7 +347,10 @@ impl ModuleDef {
|
|||
ModuleDef::Module(it) => it.id.into(),
|
||||
ModuleDef::Const(it) => it.id.into(),
|
||||
ModuleDef::Static(it) => it.id.into(),
|
||||
_ => return Vec::new(),
|
||||
ModuleDef::Variant(it) => {
|
||||
EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
|
||||
}
|
||||
ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
|
||||
};
|
||||
|
||||
let module = match self.module(db) {
|
||||
|
@ -377,10 +379,10 @@ impl ModuleDef {
|
|||
ModuleDef::Function(it) => Some(it.into()),
|
||||
ModuleDef::Const(it) => Some(it.into()),
|
||||
ModuleDef::Static(it) => Some(it.into()),
|
||||
ModuleDef::Variant(it) => Some(it.into()),
|
||||
|
||||
ModuleDef::Module(_)
|
||||
| ModuleDef::Adt(_)
|
||||
| ModuleDef::Variant(_)
|
||||
| ModuleDef::Trait(_)
|
||||
| ModuleDef::TypeAlias(_)
|
||||
| ModuleDef::Macro(_)
|
||||
|
@ -537,6 +539,30 @@ impl Module {
|
|||
}
|
||||
acc.extend(decl.diagnostics(db))
|
||||
}
|
||||
ModuleDef::Adt(adt) => {
|
||||
match adt {
|
||||
Adt::Struct(s) => {
|
||||
for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
|
||||
emit_def_diagnostic(db, acc, diag);
|
||||
}
|
||||
}
|
||||
Adt::Union(u) => {
|
||||
for diag in db.union_data_with_diagnostics(u.id).1.iter() {
|
||||
emit_def_diagnostic(db, acc, diag);
|
||||
}
|
||||
}
|
||||
Adt::Enum(e) => {
|
||||
for v in e.variants(db) {
|
||||
acc.extend(ModuleDef::Variant(v).diagnostics(db));
|
||||
}
|
||||
|
||||
for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
|
||||
emit_def_diagnostic(db, acc, diag);
|
||||
}
|
||||
}
|
||||
}
|
||||
acc.extend(decl.diagnostics(db))
|
||||
}
|
||||
_ => acc.extend(decl.diagnostics(db)),
|
||||
}
|
||||
}
|
||||
|
@ -874,7 +900,7 @@ impl Struct {
|
|||
Type::from_def(db, self.id)
|
||||
}
|
||||
|
||||
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
|
||||
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprData> {
|
||||
db.struct_data(self.id).repr.clone()
|
||||
}
|
||||
|
||||
|
@ -952,6 +978,21 @@ impl Enum {
|
|||
pub fn ty(self, db: &dyn HirDatabase) -> Type {
|
||||
Type::from_def(db, self.id)
|
||||
}
|
||||
|
||||
/// The type of the enum variant bodies.
|
||||
pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
|
||||
Type::new_for_crate(
|
||||
self.id.lookup(db.upcast()).container.krate(),
|
||||
TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
|
||||
Either::Left(builtin) => hir_def::builtin_type::BuiltinType::Int(builtin),
|
||||
Either::Right(builtin) => hir_def::builtin_type::BuiltinType::Uint(builtin),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
|
||||
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Enum {
|
||||
|
@ -960,6 +1001,12 @@ impl HasVisibility for Enum {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&Variant> for DefWithBodyId {
|
||||
fn from(&v: &Variant) -> Self {
|
||||
DefWithBodyId::VariantId(v.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Variant {
|
||||
pub(crate) parent: Enum,
|
||||
|
@ -994,6 +1041,14 @@ impl Variant {
|
|||
pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
|
||||
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
|
||||
}
|
||||
|
||||
pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
|
||||
self.source(db)?.value.expr()
|
||||
}
|
||||
|
||||
pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
|
||||
db.const_eval_variant(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Variants inherit visibility from the parent enum.
|
||||
|
@ -1034,7 +1089,7 @@ impl Adt {
|
|||
pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
|
||||
let id = AdtId::from(self);
|
||||
let mut it = args.iter().map(|t| t.ty.clone());
|
||||
let ty = TyBuilder::def_ty(db, id.into())
|
||||
let ty = TyBuilder::def_ty(db, id.into(), None)
|
||||
.fill(|x| {
|
||||
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
|
||||
match x {
|
||||
|
@ -1129,8 +1184,9 @@ pub enum DefWithBody {
|
|||
Function(Function),
|
||||
Static(Static),
|
||||
Const(Const),
|
||||
Variant(Variant),
|
||||
}
|
||||
impl_from!(Function, Const, Static for DefWithBody);
|
||||
impl_from!(Function, Const, Static, Variant for DefWithBody);
|
||||
|
||||
impl DefWithBody {
|
||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
|
@ -1138,6 +1194,7 @@ impl DefWithBody {
|
|||
DefWithBody::Const(c) => c.module(db),
|
||||
DefWithBody::Function(f) => f.module(db),
|
||||
DefWithBody::Static(s) => s.module(db),
|
||||
DefWithBody::Variant(v) => v.module(db),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1146,6 +1203,7 @@ impl DefWithBody {
|
|||
DefWithBody::Function(f) => Some(f.name(db)),
|
||||
DefWithBody::Static(s) => Some(s.name(db)),
|
||||
DefWithBody::Const(c) => c.name(db),
|
||||
DefWithBody::Variant(v) => Some(v.name(db)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1155,6 +1213,7 @@ impl DefWithBody {
|
|||
DefWithBody::Function(it) => it.ret_type(db),
|
||||
DefWithBody::Static(it) => it.ty(db),
|
||||
DefWithBody::Const(it) => it.ty(db),
|
||||
DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1163,6 +1222,7 @@ impl DefWithBody {
|
|||
DefWithBody::Function(it) => it.id.into(),
|
||||
DefWithBody::Static(it) => it.id.into(),
|
||||
DefWithBody::Const(it) => it.id.into(),
|
||||
DefWithBody::Variant(it) => it.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1379,6 +1439,7 @@ impl DefWithBody {
|
|||
DefWithBody::Function(it) => it.into(),
|
||||
DefWithBody::Static(it) => it.into(),
|
||||
DefWithBody::Const(it) => it.into(),
|
||||
DefWithBody::Variant(it) => it.into(),
|
||||
};
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
|
||||
acc.push(diag.into())
|
||||
|
@ -2485,7 +2546,7 @@ impl TypeParam {
|
|||
let resolver = self.id.parent().resolver(db.upcast());
|
||||
let ty = params.get(local_idx)?.clone();
|
||||
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
|
||||
let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
|
||||
let ty = ty.substitute(Interner, &subst);
|
||||
match ty.data(Interner) {
|
||||
GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
|
||||
_ => None,
|
||||
|
@ -2739,7 +2800,22 @@ impl Type {
|
|||
}
|
||||
|
||||
fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
|
||||
let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
|
||||
let ty_def = def.into();
|
||||
let parent_subst = match ty_def {
|
||||
TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(id) => {
|
||||
let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
|
||||
Some(subst)
|
||||
}
|
||||
ItemContainerId::ImplId(id) => {
|
||||
let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
|
||||
Some(subst)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
|
||||
Type::new(db, def, ty)
|
||||
}
|
||||
|
||||
|
@ -2879,7 +2955,11 @@ impl Type {
|
|||
alias: TypeAlias,
|
||||
) -> Option<Type> {
|
||||
let mut args = args.iter();
|
||||
let projection = TyBuilder::assoc_type_projection(db, alias.id)
|
||||
let trait_id = match alias.id.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(id) => id,
|
||||
_ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
|
||||
};
|
||||
let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
|
||||
.push(self.ty.clone())
|
||||
.fill(|x| {
|
||||
// FIXME: this code is not covered in tests.
|
||||
|
@ -2891,6 +2971,8 @@ impl Type {
|
|||
}
|
||||
})
|
||||
.build();
|
||||
// FIXME: We don't handle GATs yet.
|
||||
let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
|
||||
|
||||
let ty = db.normalize_projection(projection, self.env.clone());
|
||||
if ty.is_unknown() {
|
||||
|
@ -2940,7 +3022,7 @@ impl Type {
|
|||
|
||||
let adt = adt_id.into();
|
||||
match adt {
|
||||
Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
|
||||
Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,6 +257,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
|
||||
self.imp.original_ast_node(node)
|
||||
}
|
||||
/// Attempts to map the node out of macro expanded files.
|
||||
/// This only work for attribute expansions, as other ones do not have nodes as input.
|
||||
pub fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
|
||||
self.imp.original_syntax_node(node)
|
||||
}
|
||||
|
||||
pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
|
||||
self.imp.diagnostics_display_range(diagnostics)
|
||||
|
@ -956,6 +961,16 @@ impl<'db> SemanticsImpl<'db> {
|
|||
)
|
||||
}
|
||||
|
||||
fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
|
||||
let InFile { file_id, .. } = self.find_file(node);
|
||||
InFile::new(file_id, node).original_syntax_node(self.db.upcast()).map(
|
||||
|InFile { file_id, value }| {
|
||||
self.cache(find_root(&value), file_id);
|
||||
value
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
|
||||
let root = self.parse_or_expand(src.file_id).unwrap();
|
||||
let node = src.map(|it| it.to_node(&root));
|
||||
|
|
|
@ -115,7 +115,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
|
|||
}
|
||||
|
||||
impl SourceToDefCtx<'_, '_> {
|
||||
pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> {
|
||||
pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
|
||||
let _p = profile::span("SourceBinder::to_module_def");
|
||||
let mut mods = SmallVec::new();
|
||||
for &crate_id in self.db.relevant_crates(file).iter() {
|
||||
|
@ -130,7 +130,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||
mods
|
||||
}
|
||||
|
||||
pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
|
||||
pub(super) fn module_to_def(&self, src: InFile<ast::Module>) -> Option<ModuleId> {
|
||||
let _p = profile::span("module_to_def");
|
||||
let parent_declaration = src
|
||||
.syntax()
|
||||
|
@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||
Some(def_map.module_id(child_id))
|
||||
}
|
||||
|
||||
pub(super) fn source_file_to_def(&mut self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
|
||||
pub(super) fn source_file_to_def(&self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
|
||||
let _p = profile::span("source_file_to_def");
|
||||
let file_id = src.file_id.original_file(self.db.upcast());
|
||||
self.file_to_def(file_id).get(0).copied()
|
||||
|
@ -384,7 +384,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||
} else {
|
||||
let it = ast::Variant::cast(container.value)?;
|
||||
let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
|
||||
VariantId::from(def).into()
|
||||
DefWithBodyId::from(def).into()
|
||||
};
|
||||
Some(cont)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use hir_def::{
|
|||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||
type_ref::Mutability,
|
||||
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
|
||||
Lookup, ModuleDefId, VariantId,
|
||||
Lookup, ModuleDefId, TraitId, VariantId,
|
||||
};
|
||||
use hir_expand::{
|
||||
builtin_fn_macro::BuiltinFnLikeExpander,
|
||||
|
@ -302,10 +302,15 @@ impl SourceAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
let future_trait = db
|
||||
.lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
|
||||
.as_trait()?;
|
||||
let poll_fn = db
|
||||
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
|
||||
.as_function()?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
|
||||
// HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
|
||||
// doesn't have any generic parameters, so we skip building another subst for `poll()`.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
|
||||
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
|
||||
}
|
||||
|
||||
|
@ -321,8 +326,10 @@ impl SourceAnalyzer {
|
|||
};
|
||||
let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
|
||||
|
||||
let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
||||
let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||
}
|
||||
|
@ -337,8 +344,10 @@ impl SourceAnalyzer {
|
|||
|
||||
let lang_item_name = name![index];
|
||||
|
||||
let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
|
||||
let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
|
||||
.push(base_ty.clone())
|
||||
.push(index_ty.clone())
|
||||
.build();
|
||||
|
@ -354,10 +363,14 @@ impl SourceAnalyzer {
|
|||
let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
|
||||
let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
|
||||
|
||||
let op_fn = lang_names_for_bin_op(op)
|
||||
let (op_trait, op_fn) = lang_names_for_bin_op(op)
|
||||
.and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
|
||||
let substs =
|
||||
hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
|
||||
// HACK: subst for `index()` coincides with that for `Index` because `index()` itself
|
||||
// doesn't have any generic parameters, so we skip building another subst for `index()`.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
|
||||
.push(lhs.clone())
|
||||
.push(rhs.clone())
|
||||
.build();
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||
}
|
||||
|
@ -371,7 +384,13 @@ impl SourceAnalyzer {
|
|||
|
||||
let op_fn =
|
||||
db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
||||
let op_trait = match op_fn.lookup(db.upcast()).container {
|
||||
ItemContainerId::TraitId(id) => id,
|
||||
_ => return None,
|
||||
};
|
||||
// HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
|
||||
// doesn't have any generic parameters, so we skip building another subst for `branch()`.
|
||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||
}
|
||||
|
@ -799,9 +818,10 @@ impl SourceAnalyzer {
|
|||
db: &dyn HirDatabase,
|
||||
lang_trait: &Name,
|
||||
method_name: &Name,
|
||||
) -> Option<FunctionId> {
|
||||
db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
|
||||
.method_by_name(method_name)
|
||||
) -> Option<(TraitId, FunctionId)> {
|
||||
let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
|
||||
let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
|
||||
Some((trait_id, fn_id))
|
||||
}
|
||||
|
||||
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
|
||||
|
|
|
@ -244,6 +244,10 @@ impl<'a> SymbolCollector<'a> {
|
|||
DefWithBodyId::ConstId(id) => Some(
|
||||
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
|
||||
),
|
||||
DefWithBodyId::VariantId(id) => Some({
|
||||
let db = self.db.upcast();
|
||||
id.parent.lookup(db).source(db).value.name()?.text().into()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use ide_db::{
|
|||
},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
|
||||
|
||||
// Assist: move_format_string_arg
|
||||
|
@ -78,20 +79,26 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||
|
||||
// Extract existing arguments in macro
|
||||
let tokens =
|
||||
tt.token_trees_and_tokens().filter_map(NodeOrToken::into_token).collect_vec();
|
||||
tt.token_trees_and_tokens().collect_vec();
|
||||
|
||||
let mut existing_args: Vec<String> = vec![];
|
||||
|
||||
let mut current_arg = String::new();
|
||||
if let [_opening_bracket, format_string, _args_start_comma, tokens @ .., end_bracket] =
|
||||
if let [_opening_bracket, NodeOrToken::Token(format_string), _args_start_comma, tokens @ .., NodeOrToken::Token(end_bracket)] =
|
||||
tokens.as_slice()
|
||||
{
|
||||
for t in tokens {
|
||||
if t.kind() == COMMA {
|
||||
existing_args.push(current_arg.trim().into());
|
||||
current_arg.clear();
|
||||
} else {
|
||||
current_arg.push_str(t.text());
|
||||
match t {
|
||||
NodeOrToken::Node(n) => {
|
||||
format_to!(current_arg, "{n}");
|
||||
},
|
||||
NodeOrToken::Token(t) if t.kind() == COMMA=> {
|
||||
existing_args.push(current_arg.trim().into());
|
||||
current_arg.clear();
|
||||
},
|
||||
NodeOrToken::Token(t) => {
|
||||
current_arg.push_str(t.text());
|
||||
},
|
||||
}
|
||||
}
|
||||
existing_args.push(current_arg.trim().into());
|
||||
|
@ -261,6 +268,27 @@ fn main() {
|
|||
fn main() {
|
||||
print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
||||
}
|
||||
"#,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_tt() {
|
||||
check_assist(
|
||||
move_format_string_arg,
|
||||
&add_macro_decl(
|
||||
r#"
|
||||
fn main() {
|
||||
print!("My name is {} {x$0 + x}", stringify!(Paperino))
|
||||
}
|
||||
"#,
|
||||
),
|
||||
&add_macro_decl(
|
||||
r#"
|
||||
fn main() {
|
||||
print!("My name is {} {}"$0, stringify!(Paperino), x + x)
|
||||
}
|
||||
"#,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
use syntax::{
|
||||
ast::{self, edit::AstNodeEdit},
|
||||
AstNode, T,
|
||||
};
|
||||
|
||||
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||
|
||||
// Assist: unwrap_tuple
|
||||
//
|
||||
// Unwrap the tuple to different variables.
|
||||
//
|
||||
// ```
|
||||
// # //- minicore: result
|
||||
// fn main() {
|
||||
// $0let (foo, bar) = ("Foo", "Bar");
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// fn main() {
|
||||
// let foo = "Foo";
|
||||
// let bar = "Bar";
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||
let let_kw = ctx.find_token_syntax_at_offset(T![let])?;
|
||||
let let_stmt = let_kw.parent().and_then(ast::LetStmt::cast)?;
|
||||
let indent_level = let_stmt.indent_level().0 as usize;
|
||||
let pat = let_stmt.pat()?;
|
||||
let ty = let_stmt.ty();
|
||||
let init = let_stmt.initializer()?;
|
||||
|
||||
// This only applies for tuple patterns, types, and initializers.
|
||||
let tuple_pat = match pat {
|
||||
ast::Pat::TuplePat(pat) => pat,
|
||||
_ => return None,
|
||||
};
|
||||
let tuple_ty = ty.and_then(|it| match it {
|
||||
ast::Type::TupleType(ty) => Some(ty),
|
||||
_ => None,
|
||||
});
|
||||
let tuple_init = match init {
|
||||
ast::Expr::TupleExpr(expr) => expr,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if tuple_pat.fields().count() != tuple_init.fields().count() {
|
||||
return None;
|
||||
}
|
||||
if let Some(tys) = &tuple_ty {
|
||||
if tuple_pat.fields().count() != tys.fields().count() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let parent = let_kw.parent()?;
|
||||
|
||||
acc.add(
|
||||
AssistId("unwrap_tuple", AssistKind::RefactorRewrite),
|
||||
"Unwrap tuple",
|
||||
let_kw.text_range(),
|
||||
|edit| {
|
||||
let indents = " ".repeat(indent_level);
|
||||
|
||||
// If there is an ascribed type, insert that type for each declaration,
|
||||
// otherwise, omit that type.
|
||||
if let Some(tys) = tuple_ty {
|
||||
let mut zipped_decls = String::new();
|
||||
for (pat, ty, expr) in
|
||||
itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields())
|
||||
{
|
||||
zipped_decls.push_str(&format!("{}let {pat}: {ty} = {expr};\n", indents))
|
||||
}
|
||||
edit.replace(parent.text_range(), zipped_decls.trim());
|
||||
} else {
|
||||
let mut zipped_decls = String::new();
|
||||
for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) {
|
||||
zipped_decls.push_str(&format!("{}let {pat} = {expr};\n", indents));
|
||||
}
|
||||
edit.replace(parent.text_range(), zipped_decls.trim());
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::check_assist;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unwrap_tuples() {
|
||||
check_assist(
|
||||
unwrap_tuple,
|
||||
r#"
|
||||
fn main() {
|
||||
$0let (foo, bar) = ("Foo", "Bar");
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let foo = "Foo";
|
||||
let bar = "Bar";
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
check_assist(
|
||||
unwrap_tuple,
|
||||
r#"
|
||||
fn main() {
|
||||
$0let (foo, bar, baz) = ("Foo", "Bar", "Baz");
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let foo = "Foo";
|
||||
let bar = "Bar";
|
||||
let baz = "Baz";
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_tuple_with_types() {
|
||||
check_assist(
|
||||
unwrap_tuple,
|
||||
r#"
|
||||
fn main() {
|
||||
$0let (foo, bar): (u8, i32) = (5, 10);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let foo: u8 = 5;
|
||||
let bar: i32 = 10;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
check_assist(
|
||||
unwrap_tuple,
|
||||
r#"
|
||||
fn main() {
|
||||
$0let (foo, bar, baz): (u8, i32, f64) = (5, 10, 17.5);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let foo: u8 = 5;
|
||||
let bar: i32 = 10;
|
||||
let baz: f64 = 17.5;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -189,6 +189,7 @@ mod handlers {
|
|||
mod replace_turbofish_with_explicit_type;
|
||||
mod split_import;
|
||||
mod unmerge_match_arm;
|
||||
mod unwrap_tuple;
|
||||
mod sort_items;
|
||||
mod toggle_ignore;
|
||||
mod unmerge_use;
|
||||
|
@ -291,6 +292,7 @@ mod handlers {
|
|||
unnecessary_async::unnecessary_async,
|
||||
unwrap_block::unwrap_block,
|
||||
unwrap_result_return_type::unwrap_result_return_type,
|
||||
unwrap_tuple::unwrap_tuple,
|
||||
wrap_return_type_in_result::wrap_return_type_in_result,
|
||||
// These are manually sorted for better priorities. By default,
|
||||
// priority is determined by the size of the target range (smaller
|
||||
|
|
|
@ -96,8 +96,10 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
|
|||
});
|
||||
|
||||
let actual = {
|
||||
let source_change =
|
||||
assist.source_change.expect("Assist did not contain any source changes");
|
||||
let source_change = assist
|
||||
.source_change
|
||||
.filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
|
||||
.expect("Assist did not contain any source changes");
|
||||
let mut actual = before;
|
||||
if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
|
||||
source_file_edit.apply(&mut actual);
|
||||
|
@ -140,8 +142,10 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult<'_>, assist_la
|
|||
|
||||
match (assist, expected) {
|
||||
(Some(assist), ExpectedResult::After(after)) => {
|
||||
let source_change =
|
||||
assist.source_change.expect("Assist did not contain any source changes");
|
||||
let source_change = assist
|
||||
.source_change
|
||||
.filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
|
||||
.expect("Assist did not contain any source changes");
|
||||
let skip_header = source_change.source_file_edits.len() == 1
|
||||
&& source_change.file_system_edits.len() == 0;
|
||||
|
||||
|
|
|
@ -2386,6 +2386,25 @@ fn foo() -> i32 { 42i32 }
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_unwrap_tuple() {
|
||||
check_doc_test(
|
||||
"unwrap_tuple",
|
||||
r#####"
|
||||
//- minicore: result
|
||||
fn main() {
|
||||
$0let (foo, bar) = ("Foo", "Bar");
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
fn main() {
|
||||
let foo = "Foo";
|
||||
let bar = "Bar";
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_wrap_return_type_in_result() {
|
||||
check_doc_test(
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue