Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for specifying generic arg in path segment #1017

Open
wants to merge 1 commit into
base: fe-v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 15 additions & 10 deletions crates/driver2/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ use common::{
InputDb, InputFile,
};
use cs::{diagnostic as cs_diag, files as cs_files};
use hir::diagnostics::DiagnosticVoucher;
use hir::{diagnostics::DiagnosticVoucher, SpannedHirDb};

use crate::{DriverDataBase, DriverDb};
use crate::DriverDb;

pub trait ToCsDiag {
fn to_cs(&self, db: &dyn DriverDb) -> cs_diag::Diagnostic<InputFile>;
fn to_cs(&self, db: &dyn SpannedInputDb) -> cs_diag::Diagnostic<InputFile>;
}

pub trait SpannedInputDb: SpannedHirDb + InputDb {}
impl<T> SpannedInputDb for T where T: SpannedHirDb + InputDb {}

impl<T> ToCsDiag for T
where
T: for<'db> DiagnosticVoucher<'db>,
{
fn to_cs(&self, db: &dyn DriverDb) -> cs_diag::Diagnostic<InputFile> {
fn to_cs(&self, db: &dyn SpannedInputDb) -> cs_diag::Diagnostic<InputFile> {
let complete = self.to_complete(db.as_spanned_hir_db());

let severity = convert_severity(complete.severity);
Expand Down Expand Up @@ -67,25 +70,27 @@ pub fn file_line_starts(db: &dyn DriverDb, file: InputFile) -> Vec<usize> {
cs::files::line_starts(file.text(db.as_input_db())).collect()
}

impl<'db> cs_files::Files<'db> for DriverDataBase {
pub struct CsDbWrapper<'a>(pub &'a dyn DriverDb);

impl<'db> cs_files::Files<'db> for CsDbWrapper<'db> {
type FileId = InputFile;
type Name = &'db Utf8Path;
type Source = &'db str;

fn name(&'db self, file_id: Self::FileId) -> Result<Self::Name, cs_files::Error> {
Ok(file_id.path(self.as_input_db()).as_path())
Ok(file_id.path(self.0.as_input_db()).as_path())
}

fn source(&'db self, file_id: Self::FileId) -> Result<Self::Source, cs_files::Error> {
Ok(file_id.text(self.as_input_db()))
Ok(file_id.text(self.0.as_input_db()))
}

fn line_index(
&'db self,
file_id: Self::FileId,
byte_index: usize,
) -> Result<usize, cs_files::Error> {
let starts = file_line_starts(self, file_id);
let starts = file_line_starts(self.0, file_id);
Ok(starts
.binary_search(&byte_index)
.unwrap_or_else(|next_line| next_line - 1))
Expand All @@ -96,7 +101,7 @@ impl<'db> cs_files::Files<'db> for DriverDataBase {
file_id: Self::FileId,
line_index: usize,
) -> Result<Range<usize>, cs_files::Error> {
let line_starts = file_line_starts(self, file_id);
let line_starts = file_line_starts(self.0, file_id);

let start = *line_starts
.get(line_index)
Expand All @@ -106,7 +111,7 @@ impl<'db> cs_files::Files<'db> for DriverDataBase {
})?;

let end = if line_index == line_starts.len() - 1 {
file_id.text(self.as_input_db()).len()
file_id.text(self.0.as_input_db()).len()
} else {
*line_starts
.get(line_index + 1)
Expand Down
5 changes: 3 additions & 2 deletions crates/driver2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use common::{
input::{IngotKind, Version},
InputDb, InputFile, InputIngot,
};
pub use diagnostics::CsDbWrapper;
use hir::{
analysis_pass::AnalysisPassManager, diagnostics::DiagnosticVoucher, hir_def::TopLevelMod,
lower::map_file_to_mod, HirDb, LowerHirDb, ParsingPass, SpannedHirDb,
Expand Down Expand Up @@ -109,7 +110,7 @@ impl<'db> DiagnosticsCollection<'db> {
let config = term::Config::default();

for diag in self.finalize(db) {
term::emit(&mut buffer, &config, db, &diag.to_cs(db)).unwrap();
term::emit(&mut buffer, &config, &CsDbWrapper(db), &diag.to_cs(db)).unwrap();
}

eprintln!("{}", std::str::from_utf8(buffer.as_slice()).unwrap());
Expand All @@ -122,7 +123,7 @@ impl<'db> DiagnosticsCollection<'db> {
let config = term::Config::default();

for diag in self.finalize(db) {
term::emit(&mut buffer, &config, db, &diag.to_cs(db)).unwrap();
term::emit(&mut buffer, &config, &CsDbWrapper(db), &diag.to_cs(db)).unwrap();
}

std::str::from_utf8(buffer.as_slice()).unwrap().to_string()
Expand Down
2 changes: 2 additions & 0 deletions crates/hir-analysis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ common = { path = "../common2", package = "fe-common2" }
[dev-dependencies]
codespan-reporting = "0.11"
dir-test = "0.3"
# xxx move cs diagnostics utils
driver = { path = "../driver2", package = "fe-driver2" }
28 changes: 18 additions & 10 deletions crates/hir-analysis/src/name_resolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use hir::{
analysis_pass::ModuleAnalysisPass,
diagnostics::DiagnosticVoucher,
hir_def::{
scope_graph::ScopeId, Expr, ExprId, GenericArgListId, IdentId, IngotId, ItemKind, Partial,
Pat, PatId, PathId, TopLevelMod, TraitRefId, TypeId,
scope_graph::ScopeId, Expr, ExprId, GenericArgListId, IngotId, ItemKind, Pat, PatId,
PathId, PathSegmentId, TopLevelMod, TraitRefId, TypeId,
},
visitor::prelude::*,
};
Expand Down Expand Up @@ -51,7 +51,7 @@ pub fn resolve_path_early<'db>(
/// contains some errors; it's always reported from [`PathAnalysisPass`].
pub fn resolve_segments_early<'db>(
db: &'db dyn HirAnalysisDb,
segments: &[Partial<IdentId<'db>>],
segments: &[PathSegmentId<'db>],
scope: ScopeId<'db>,
) -> EarlyResolvedPath<'db> {
// Obtain cache store for the given scope.
Expand Down Expand Up @@ -218,7 +218,7 @@ struct EarlyPathVisitor<'db, 'a> {
/// diagnostics.
already_conflicted: FxHashSet<ScopeId<'db>>,
}

// xxx generic args?
impl<'db, 'a> EarlyPathVisitor<'db, 'a> {
fn new(db: &'db dyn HirAnalysisDb, importer: &'a DefaultImporter) -> Self {
let resolver = name_resolver::NameResolver::new(db, importer);
Expand All @@ -240,8 +240,12 @@ impl<'db, 'a> EarlyPathVisitor<'db, 'a> {
bucket: NameResBucket<'db>,
) {
let path_kind = self.path_ctxt.last().unwrap();
let last_seg_idx = path.len(self.db.as_hir_db()) - 1;
let last_seg_ident = *path.segments(self.db.as_hir_db())[last_seg_idx].unwrap();
let hir_db = self.db.as_hir_db();
let last_seg_idx = path.len(hir_db) - 1;
let last_seg_ident = path
.last_segment(hir_db)
.and_then(|seg| seg.ident(hir_db).to_opt())
.unwrap();
let span = span.segment(last_seg_idx).into();

if bucket.is_empty() {
Expand Down Expand Up @@ -488,11 +492,12 @@ impl<'db, 'a> Visitor<'db> for EarlyPathVisitor<'db, 'a> {
Err(err) => {
let failed_at = err.failed_at;
let span = ctxt.span().unwrap().segment(failed_at);
let ident = path.segments(self.db.as_hir_db())[failed_at];
let hir_db = self.db.as_hir_db();
let ident = path.segments(hir_db)[failed_at].ident(hir_db);

let diag = match err.kind {
NameResolutionError::NotFound => {
if path.len(self.db.as_hir_db()) == 1
if path.len(hir_db) == 1
&& matches!(
self.path_ctxt.last().unwrap(),
ExpectedPathKind::Expr | ExpectedPathKind::Pat
Expand Down Expand Up @@ -536,9 +541,11 @@ impl<'db, 'a> Visitor<'db> for EarlyPathVisitor<'db, 'a> {
};

if let Some((idx, res)) = resolved_path.find_invisible_segment(self.db) {
let hir_db = self.db.as_hir_db();
let span = ctxt.span().unwrap().segment(idx);
let ident = path.segments(self.db.as_hir_db())[idx].unwrap();
let diag = NameResDiag::invisible(span.into(), *ident, res.derived_from(self.db));
let ident = path.segments(hir_db)[idx].ident(hir_db);
let diag =
NameResDiag::invisible(span.into(), *ident.unwrap(), res.derived_from(self.db));
self.diags.push(diag);
return;
}
Expand Down Expand Up @@ -572,6 +579,7 @@ impl ExpectedPathKind {
}
}

// xxx either::right == err?
fn pick(self, bucket: NameResBucket) -> Either<NameRes, NameRes> {
debug_assert!(!bucket.is_empty());

Expand Down
19 changes: 12 additions & 7 deletions crates/hir-analysis/src/name_resolution/path_resolver.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(unused)]
use hir::hir_def::{scope_graph::ScopeId, IdentId, Partial, PathId};
use hir::hir_def::{scope_graph::ScopeId, IdentId, Partial, PathId, PathSegmentId};

use super::{
name_resolver::{
Expand Down Expand Up @@ -108,7 +108,7 @@ impl<'db, 'a, 'b, 'c> EarlyPathResolver<'db, 'a, 'b, 'c> {
/// Resolves the given `segments` in the given `scope`.
pub(super) fn resolve_segments(
&mut self,
segments: &[Partial<IdentId<'db>>],
segments: &[PathSegmentId<'db>],
scope: ScopeId<'db>,
) -> PathResolutionResult<'db, EarlyResolvedPathWithTrajectory<'db>> {
let mut i_path = IntermediatePath::new(self.db, segments, scope);
Expand Down Expand Up @@ -155,16 +155,17 @@ impl<'db, 'a, 'b, 'c> EarlyPathResolver<'db, 'a, 'b, 'c> {
}

struct IntermediatePath<'db, 'a> {
path: &'a [Partial<IdentId<'db>>],
path: &'a [PathSegmentId<'db>],
idx: usize,
current_res: NameRes<'db>,
trajectory: Vec<NameRes<'db>>,
}

// xxx generic args?
impl<'db, 'a> IntermediatePath<'db, 'a> {
fn new(
db: &'db dyn HirAnalysisDb,
path: &'a [Partial<IdentId<'db>>],
path: &'a [PathSegmentId<'db>],
scope: ScopeId<'db>,
) -> Self {
let domain = NameDomain::from_scope(db, scope);
Expand All @@ -181,17 +182,21 @@ impl<'db, 'a> IntermediatePath<'db, 'a> {
}

fn starts_with(&self, db: &dyn HirAnalysisDb, ident: IdentId) -> bool {
let Some(Partial::Present(first_seg)) = self.path.first() else {
let Some(first_seg) = self
.path
.first()
.and_then(|seg| seg.ident(db.as_hir_db()).to_opt())
else {
return false;
};

*first_seg == ident
first_seg == ident
}

/// Make a `NameQuery` to resolve the current segment.
fn make_query(&self, db: &'db dyn HirAnalysisDb) -> PathResolutionResult<'db, NameQuery<'db>> {
debug_assert!(self.state(db) != IntermediatePathState::Partial);
let Partial::Present(name) = self.path[self.idx] else {
let Partial::Present(name) = self.path[self.idx].ident(db.as_hir_db()) else {
return Err(PathResolutionError::new(
NameResolutionError::Invalid,
self.idx,
Expand Down
4 changes: 3 additions & 1 deletion crates/hir-analysis/src/ty/ty_check/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,9 @@ impl<'db> LocalBinding<'db> {
else {
unreachable!();
};
*path.last_segment(hir_db).unwrap()
path.last_segment(hir_db)
.and_then(|seg| seg.ident(hir_db).to_opt())
.unwrap()
}

Self::Param { idx, .. } => {
Expand Down
35 changes: 20 additions & 15 deletions crates/hir-analysis/src/ty/ty_check/expr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use either::Either;
use hir::hir_def::{
ArithBinOp, BinOp, Expr, ExprId, FieldIndex, IdentId, Partial, PathId, UnOp, VariantKind,
ArithBinOp, BinOp, Expr, ExprId, FieldIndex, IdentId, Partial, PathId, PathSegmentId, UnOp,
VariantKind,
};

use super::{
Expand Down Expand Up @@ -251,7 +252,7 @@ impl<'db> TyChecker<'db> {
}

fn check_call(&mut self, expr: ExprId, expr_data: &Expr<'db>) -> ExprProp<'db> {
let Expr::Call(callee, generic_args, args) = expr_data else {
let Expr::Call(callee, args) = expr_data else {
unreachable!()
};
let callee_ty = self.fresh_ty();
Expand All @@ -261,20 +262,21 @@ impl<'db> TyChecker<'db> {
return ExprProp::invalid(self.db);
}

let mut callable =
match Callable::new(self.db, callee_ty, callee.lazy_span(self.body()).into()) {
Ok(callable) => callable,
Err(diag) => {
self.push_diag(diag);
return ExprProp::invalid(self.db);
}
};
let callable = match Callable::new(self.db, callee_ty, callee.lazy_span(self.body()).into())
{
Ok(callable) => callable,
Err(diag) => {
self.push_diag(diag);
return ExprProp::invalid(self.db);
}
};

let call_span = expr.lazy_span(self.body()).into_call_expr();

if !callable.unify_generic_args(self, *generic_args, call_span.generic_args()) {
return ExprProp::invalid(self.db);
}
// xxx
// if !callable.unify_generic_args(self, *generic_args, call_span.generic_args()) {
// return ExprProp::invalid(self.db);
// }

callable.check_args(self, args, call_span.args_moved(), None);

Expand Down Expand Up @@ -948,7 +950,10 @@ pub(crate) trait TraitOps {
fn trait_path<'db>(&self, db: &'db dyn HirAnalysisDb) -> PathId<'db> {
let hir_db = db.as_hir_db();
let path = std_ops_path(db);
path.push(hir_db, self.trait_name(db))
path.push(
hir_db,
PathSegmentId::from_ident(hir_db, self.trait_name(db)),
)
}

fn trait_name<'db>(&self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> {
Expand Down Expand Up @@ -1067,7 +1072,7 @@ fn std_ops_path(db: &dyn HirAnalysisDb) -> PathId {
let hir_db = db.as_hir_db();
let path_data: Vec<_> = ["std", "ops"]
.into_iter()
.map(|s| Partial::Present(IdentId::new(hir_db, s.to_string())))
.map(|s| PathSegmentId::from_ident(hir_db, IdentId::new(hir_db, s.to_string())))
.collect();

PathId::new(hir_db, path_data)
Expand Down
Loading
Loading