From d3160711473ce7a36f1a9d88942a39bda31e021f Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 15 Oct 2024 10:16:09 -0300 Subject: [PATCH 1/5] Move UsageTracker outside of NodeInterner --- .../noirc_frontend/src/elaborator/comptime.rs | 4 ++++ .../src/elaborator/expressions.rs | 2 +- compiler/noirc_frontend/src/elaborator/mod.rs | 8 +++++-- .../noirc_frontend/src/elaborator/scope.rs | 9 ++------ .../src/hir/def_collector/dc_crate.rs | 10 ++++----- .../src/hir/def_collector/dc_mod.rs | 18 ++++++++++------ compiler/noirc_frontend/src/hir/mod.rs | 4 ++++ compiler/noirc_frontend/src/node_interner.rs | 11 ---------- compiler/noirc_frontend/src/tests.rs | 21 +++++++++++++++++++ compiler/noirc_frontend/src/usage_tracker.rs | 2 +- tooling/lsp/src/lib.rs | 2 ++ tooling/lsp/src/notifications/mod.rs | 1 + tooling/lsp/src/requests/code_action.rs | 5 +++++ .../code_action/remove_unused_import.rs | 2 +- tooling/lsp/src/requests/mod.rs | 8 +++++++ 15 files changed, 73 insertions(+), 34 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 65cb6072c62..e7645fdfcb9 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -91,6 +91,7 @@ impl<'context> Elaborator<'context> { let mut elaborator = Elaborator::new( self.interner, self.def_maps, + self.usage_tracker, self.crate_id, self.debug_comptime_in_file, self.interpreter_call_stack.clone(), @@ -412,6 +413,7 @@ impl<'context> Elaborator<'context> { if let Some(id) = dc_mod::collect_function( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), + &mut self.usage_tracker, &function, module_id, self.file, @@ -461,6 +463,7 @@ impl<'context> Elaborator<'context> { let (global, error) = dc_mod::collect_global( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), + &mut self.usage_tracker, Documented::new(global, item.doc_comments), visibility, self.file, @@ -477,6 +480,7 @@ impl<'context> Elaborator<'context> { if let Some((type_id, the_struct)) = dc_mod::collect_struct( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), + &mut self.usage_tracker, Documented::new(struct_def, item.doc_comments), self.file, self.local_module, diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 6dfd295db6f..ff482dca4fb 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -591,7 +591,7 @@ impl<'context> Elaborator<'context> { pub(super) fn mark_struct_as_constructed(&mut self, struct_type: Shared) { let struct_type = struct_type.borrow(); let parent_module_id = struct_type.id.parent_module_id(self.def_maps); - self.interner.usage_tracker.mark_as_used(parent_module_id, &struct_type.name); + self.usage_tracker.mark_as_used(parent_module_id, &struct_type.name); } /// Resolve all the fields of a struct constructor expression. diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 2a723286d8b..5af435f9201 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -5,7 +5,8 @@ use std::{ use crate::{ ast::ItemVisibility, hir::resolution::import::PathResolutionItem, - hir_def::traits::ResolvedTraitBound, StructField, StructType, TypeBindings, + hir_def::traits::ResolvedTraitBound, usage_tracker::UsageTracker, StructField, StructType, + TypeBindings, }; use crate::{ ast::{ @@ -84,8 +85,8 @@ pub struct Elaborator<'context> { pub(crate) errors: Vec<(CompilationError, FileId)>, pub(crate) interner: &'context mut NodeInterner, - pub(crate) def_maps: &'context mut DefMaps, + pub(crate) usage_tracker: &'context mut UsageTracker, pub(crate) file: FileId, @@ -183,6 +184,7 @@ impl<'context> Elaborator<'context> { pub fn new( interner: &'context mut NodeInterner, def_maps: &'context mut DefMaps, + usage_tracker: &'context mut UsageTracker, crate_id: CrateId, debug_comptime_in_file: Option, interpreter_call_stack: im::Vector, @@ -192,6 +194,7 @@ impl<'context> Elaborator<'context> { errors: Vec::new(), interner, def_maps, + usage_tracker, file: FileId::dummy(), in_unsafe_block: false, nested_loops: 0, @@ -221,6 +224,7 @@ impl<'context> Elaborator<'context> { Self::new( &mut context.def_interner, &mut context.def_maps, + &mut context.usage_tracker, crate_id, debug_comptime_in_file, im::Vector::new(), diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index 8e033c914be..ca256302041 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -86,12 +86,7 @@ impl<'context> Elaborator<'context> { let resolver = StandardPathResolver::new(module_id, self_type_module_id); if !self.interner.lsp_mode { - return resolver.resolve( - self.def_maps, - path, - &mut self.interner.usage_tracker, - &mut None, - ); + return resolver.resolve(self.def_maps, path, &mut self.usage_tracker, &mut None); } let last_segment = path.last_ident(); @@ -102,7 +97,7 @@ impl<'context> Elaborator<'context> { let path_resolution = resolver.resolve( self.def_maps, path.clone(), - &mut self.interner.usage_tracker, + &mut self.usage_tracker, &mut Some(&mut references), ); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 20c162fbd3a..347bf90f849 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -354,7 +354,7 @@ impl DefCollector { crate_id, &collected_import, &context.def_maps, - &mut context.def_interner.usage_tracker, + &mut context.usage_tracker, &mut Some(&mut references), ); @@ -376,7 +376,7 @@ impl DefCollector { crate_id, &collected_import, &context.def_maps, - &mut context.def_interner.usage_tracker, + &mut context.usage_tracker, &mut None, ) }; @@ -421,7 +421,7 @@ impl DefCollector { krate: crate_id, local_id: resolved_import.module_scope, }; - context.def_interner.usage_tracker.add_unused_item( + context.usage_tracker.add_unused_item( module_id, name.clone(), UnusedItem::Import, @@ -501,7 +501,7 @@ impl DefCollector { crate_id: CrateId, errors: &mut Vec<(CompilationError, FileId)>, ) { - let unused_imports = context.def_interner.unused_items().iter(); + let unused_imports = context.usage_tracker.unused_items().iter(); let unused_imports = unused_imports.filter(|(module_id, _)| module_id.krate == crate_id); errors.extend(unused_imports.flat_map(|(module_id, usage_tracker)| { @@ -561,7 +561,7 @@ fn inject_prelude( ModuleId { krate: crate_id, local_id: crate_root }, None, path, - &mut context.def_interner.usage_tracker, + &mut context.usage_tracker, &mut None, ) { assert!(errors.is_empty(), "Tried to add private item to prelude"); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 825a8414fe0..56b397d079e 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -18,7 +18,7 @@ use crate::ast::{ use crate::hir::resolution::errors::ResolverError; use crate::node_interner::{ModuleAttributes, NodeInterner, ReferenceId, StructId}; use crate::token::SecondaryAttribute; -use crate::usage_tracker::UnusedItem; +use crate::usage_tracker::{UnusedItem, UsageTracker}; use crate::{ graph::CrateId, hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait}, @@ -147,6 +147,7 @@ impl<'a> ModCollector<'a> { let (global, error) = collect_global( &mut context.def_interner, &mut self.def_collector.def_map, + &mut context.usage_tracker, global, visibility, self.file_id, @@ -246,6 +247,7 @@ impl<'a> ModCollector<'a> { let Some(func_id) = collect_function( &mut context.def_interner, &mut self.def_collector.def_map, + &mut context.usage_tracker, &function.item, module, self.file_id, @@ -282,6 +284,7 @@ impl<'a> ModCollector<'a> { if let Some((id, the_struct)) = collect_struct( &mut context.def_interner, &mut self.def_collector.def_map, + &mut context.usage_tracker, struct_definition, self.file_id, self.module_id, @@ -336,7 +339,7 @@ impl<'a> ModCollector<'a> { ); let parent_module_id = ModuleId { krate, local_id: self.module_id }; - context.def_interner.usage_tracker.add_unused_item( + context.usage_tracker.add_unused_item( parent_module_id, name.clone(), UnusedItem::TypeAlias(type_alias_id), @@ -412,7 +415,7 @@ impl<'a> ModCollector<'a> { ); let parent_module_id = ModuleId { krate, local_id: self.module_id }; - context.def_interner.usage_tracker.add_unused_item( + context.usage_tracker.add_unused_item( parent_module_id, name.clone(), UnusedItem::Trait(trait_id), @@ -900,6 +903,7 @@ fn push_child_module( pub fn collect_function( interner: &mut NodeInterner, def_map: &mut CrateDefMap, + usage_tracker: &mut UsageTracker, function: &NoirFunction, module: ModuleId, file: FileId, @@ -932,7 +936,7 @@ pub fn collect_function( if !is_test && !is_entry_point_function { let item = UnusedItem::Function(func_id); - interner.usage_tracker.add_unused_item(module, name.clone(), item, visibility); + usage_tracker.add_unused_item(module, name.clone(), item, visibility); } interner.set_doc_comments(ReferenceId::Function(func_id), doc_comments); @@ -953,6 +957,7 @@ pub fn collect_function( pub fn collect_struct( interner: &mut NodeInterner, def_map: &mut CrateDefMap, + usage_tracker: &mut UsageTracker, struct_definition: Documented, file_id: FileId, module_id: LocalModuleId, @@ -1015,7 +1020,7 @@ pub fn collect_struct( let parent_module_id = ModuleId { krate, local_id: module_id }; if !unresolved.struct_def.is_abi() { - interner.usage_tracker.add_unused_item( + usage_tracker.add_unused_item( parent_module_id, name.clone(), UnusedItem::Struct(id), @@ -1194,6 +1199,7 @@ pub(crate) fn collect_trait_impl_items( pub(crate) fn collect_global( interner: &mut NodeInterner, def_map: &mut CrateDefMap, + usage_tracker: &mut UsageTracker, global: Documented, visibility: ItemVisibility, file_id: FileId, @@ -1221,7 +1227,7 @@ pub(crate) fn collect_global( if !is_abi { let parent_module_id = ModuleId { krate: crate_id, local_id: module_id }; - interner.usage_tracker.add_unused_item( + usage_tracker.add_unused_item( parent_module_id, name, UnusedItem::Global(global_id), diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index 015b7deb6e0..2bd1a852f05 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -11,6 +11,7 @@ use crate::graph::{CrateGraph, CrateId}; use crate::hir_def::function::FuncMeta; use crate::node_interner::{FuncId, NodeInterner, StructId}; use crate::parser::ParserError; +use crate::usage_tracker::UsageTracker; use crate::{Generics, Kind, ParsedModule, ResolvedGeneric, TypeVariable}; use def_collector::dc_crate::CompilationError; use def_map::{Contract, CrateDefMap}; @@ -33,6 +34,7 @@ pub struct Context<'file_manager, 'parsed_files> { pub def_interner: NodeInterner, pub crate_graph: CrateGraph, pub def_maps: BTreeMap, + pub usage_tracker: UsageTracker, // In the WASM context, we take ownership of the file manager, // which is why this needs to be a Cow. In all use-cases, the file manager // is read-only however, once it has been passed to the Context. @@ -64,6 +66,7 @@ impl Context<'_, '_> { Context { def_interner: NodeInterner::default(), def_maps: BTreeMap::new(), + usage_tracker: UsageTracker::default(), visited_files: BTreeMap::new(), crate_graph: CrateGraph::default(), file_manager: Cow::Owned(file_manager), @@ -80,6 +83,7 @@ impl Context<'_, '_> { Context { def_interner: NodeInterner::default(), def_maps: BTreeMap::new(), + usage_tracker: UsageTracker::default(), visited_files: BTreeMap::new(), crate_graph: CrateGraph::default(), file_manager: Cow::Borrowed(file_manager), diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index 68510f2ffbd..c743d564339 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -25,8 +25,6 @@ use crate::hir::def_map::{LocalModuleId, ModuleDefId, ModuleId}; use crate::hir::type_check::generics::TraitGenerics; use crate::hir_def::traits::NamedType; use crate::hir_def::traits::ResolvedTraitBound; -use crate::usage_tracker::UnusedItem; -use crate::usage_tracker::UsageTracker; use crate::QuotedType; use crate::ast::{BinaryOpKind, FunctionDefinition, ItemVisibility}; @@ -271,8 +269,6 @@ pub struct NodeInterner { /// share the same global values. pub(crate) comptime_scopes: Vec>, - pub(crate) usage_tracker: UsageTracker, - /// Captures the documentation comments for each module, struct, trait, function, etc. pub(crate) doc_comments: HashMap>, } @@ -680,7 +676,6 @@ impl Default for NodeInterner { auto_import_names: HashMap::default(), comptime_scopes: vec![HashMap::default()], trait_impl_associated_types: HashMap::default(), - usage_tracker: UsageTracker::default(), doc_comments: HashMap::default(), } } @@ -2320,12 +2315,6 @@ impl NodeInterner { pub fn doc_comments(&self, id: ReferenceId) -> Option<&Vec> { self.doc_comments.get(&id) } - - pub fn unused_items( - &self, - ) -> &std::collections::HashMap> { - self.usage_tracker.unused_items() - } } impl Methods { diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 5ce3ec6686c..7873d9d1755 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -3562,3 +3562,24 @@ fn alias_in_let_pattern() { "#; assert_no_errors(src); } + +#[test] +fn use_type_alias_in_method_call() { + let src = r#" + pub struct Foo { + } + + impl Foo { + fn new() { + Foo {} + } + } + + type Bar = Foo; + + fn main() { + Bar::new(); + } + "#; + assert_no_errors(src); +} diff --git a/compiler/noirc_frontend/src/usage_tracker.rs b/compiler/noirc_frontend/src/usage_tracker.rs index 0a112c6937d..fa87ca6961b 100644 --- a/compiler/noirc_frontend/src/usage_tracker.rs +++ b/compiler/noirc_frontend/src/usage_tracker.rs @@ -73,7 +73,7 @@ impl UsageTracker { }; } - pub(crate) fn unused_items(&self) -> &HashMap> { + pub fn unused_items(&self) -> &HashMap> { &self.unused_items } } diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index a85b9d043b9..90ccacc28a3 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -42,6 +42,7 @@ use noirc_frontend::{ }, node_interner::NodeInterner, parser::ParserError, + usage_tracker::UsageTracker, ParsedModule, }; use rayon::prelude::*; @@ -113,6 +114,7 @@ struct PackageCacheData { crate_graph: CrateGraph, node_interner: NodeInterner, def_maps: BTreeMap, + usage_tracker: UsageTracker, } impl LspState { diff --git a/tooling/lsp/src/notifications/mod.rs b/tooling/lsp/src/notifications/mod.rs index d228eb564e6..f6fdd082d0b 100644 --- a/tooling/lsp/src/notifications/mod.rs +++ b/tooling/lsp/src/notifications/mod.rs @@ -166,6 +166,7 @@ pub(crate) fn process_workspace_for_noir_document( crate_graph: context.crate_graph, node_interner: context.def_interner, def_maps: context.def_maps, + usage_tracker: context.usage_tracker, }, ); diff --git a/tooling/lsp/src/requests/code_action.rs b/tooling/lsp/src/requests/code_action.rs index 5c2831be7e9..38cc6bddf64 100644 --- a/tooling/lsp/src/requests/code_action.rs +++ b/tooling/lsp/src/requests/code_action.rs @@ -19,6 +19,7 @@ use noirc_frontend::{ graph::CrateId, hir::def_map::{CrateDefMap, LocalModuleId, ModuleId}, node_interner::NodeInterner, + usage_tracker::UsageTracker, }; use noirc_frontend::{ parser::{Item, ItemKind, ParsedSubModule}, @@ -62,6 +63,7 @@ pub(crate) fn on_code_action_request( args.crate_id, args.def_maps, args.interner, + args.usage_tracker, ); finder.find(&parsed_module) }) @@ -82,6 +84,7 @@ struct CodeActionFinder<'a> { module_id: ModuleId, def_maps: &'a BTreeMap, interner: &'a NodeInterner, + usage_tracker: &'a UsageTracker, /// How many nested `mod` we are in deep nesting: usize, /// The line where an auto_import must be inserted @@ -103,6 +106,7 @@ impl<'a> CodeActionFinder<'a> { krate: CrateId, def_maps: &'a BTreeMap, interner: &'a NodeInterner, + usage_tracker: &'a UsageTracker, ) -> Self { // Find the module the current file belongs to let def_map = &def_maps[&krate]; @@ -124,6 +128,7 @@ impl<'a> CodeActionFinder<'a> { module_id, def_maps, interner, + usage_tracker, nesting: 0, auto_import_line: 0, use_segment_positions: UseSegmentPositions::default(), diff --git a/tooling/lsp/src/requests/code_action/remove_unused_import.rs b/tooling/lsp/src/requests/code_action/remove_unused_import.rs index c1a3c87d142..4822a9d61ec 100644 --- a/tooling/lsp/src/requests/code_action/remove_unused_import.rs +++ b/tooling/lsp/src/requests/code_action/remove_unused_import.rs @@ -24,7 +24,7 @@ impl<'a> CodeActionFinder<'a> { return; } - let Some(unused_items) = self.interner.unused_items().get(&self.module_id) else { + let Some(unused_items) = self.usage_tracker.unused_items().get(&self.module_id) else { return; }; diff --git a/tooling/lsp/src/requests/mod.rs b/tooling/lsp/src/requests/mod.rs index 0ee66f1f618..891810e0ead 100644 --- a/tooling/lsp/src/requests/mod.rs +++ b/tooling/lsp/src/requests/mod.rs @@ -18,6 +18,7 @@ use nargo_fmt::Config; use noirc_frontend::graph::CrateId; use noirc_frontend::hir::def_map::CrateDefMap; +use noirc_frontend::usage_tracker::UsageTracker; use noirc_frontend::{graph::Dependency, node_interner::NodeInterner}; use serde::{Deserialize, Serialize}; @@ -416,6 +417,7 @@ pub(crate) struct ProcessRequestCallbackArgs<'a> { crate_name: String, dependencies: &'a Vec, def_maps: &'a BTreeMap, + usage_tracker: &'a UsageTracker, } pub(crate) fn process_request( @@ -452,6 +454,7 @@ where let file_manager = &workspace_cache_data.file_manager; let interner = &package_cache_data.node_interner; let def_maps = &package_cache_data.def_maps; + let usage_tracker = &package_cache_data.usage_tracker; let crate_graph = &package_cache_data.crate_graph; let crate_id = package_cache_data.crate_id; @@ -472,6 +475,7 @@ where crate_name: package.name.to_string(), dependencies: &crate_graph[crate_id].dependencies, def_maps, + usage_tracker, })) } @@ -506,14 +510,17 @@ where let interner; let def_maps; + let usage_tracker; if let Some(package_cache) = state.package_cache.get(&package.root_dir) { interner = &package_cache.node_interner; def_maps = &package_cache.def_maps; + usage_tracker = &package_cache.usage_tracker; } else { // We ignore the warnings and errors produced by compilation while resolving the definition let _ = noirc_driver::check_crate(&mut context, crate_id, &Default::default()); interner = &context.def_interner; def_maps = &context.def_maps; + usage_tracker = &context.usage_tracker; } let files = workspace_file_manager.as_file_map(); @@ -533,6 +540,7 @@ where crate_name: package.name.to_string(), dependencies: &context.crate_graph[crate_id].dependencies, def_maps, + usage_tracker, })) } From 8c11858b098fde2ce74b5c13e7f73523e8efd3eb Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 29 Oct 2024 16:01:42 -0300 Subject: [PATCH 2/5] Allow using type aliaes in paths --- .../noirc_frontend/src/elaborator/scope.rs | 11 +++- .../src/hir/def_collector/dc_crate.rs | 3 ++ .../src/hir/def_collector/dc_mod.rs | 1 + .../src/hir/resolution/import.rs | 50 +++++++++++++++++-- .../src/hir/resolution/path_resolver.rs | 16 ++++-- compiler/noirc_frontend/src/tests.rs | 8 ++- tooling/lsp/src/attribute_reference_finder.rs | 9 ++-- tooling/lsp/src/requests/goto_definition.rs | 1 + tooling/lsp/src/requests/hover.rs | 1 + 9 files changed, 87 insertions(+), 13 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index ca256302041..ccba14ccd5b 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -86,7 +86,13 @@ impl<'context> Elaborator<'context> { let resolver = StandardPathResolver::new(module_id, self_type_module_id); if !self.interner.lsp_mode { - return resolver.resolve(self.def_maps, path, &mut self.usage_tracker, &mut None); + return resolver.resolve( + self.interner, + self.def_maps, + path, + &mut self.usage_tracker, + &mut None, + ); } let last_segment = path.last_ident(); @@ -95,9 +101,10 @@ impl<'context> Elaborator<'context> { let mut references: Vec<_> = Vec::new(); let path_resolution = resolver.resolve( + self.interner, self.def_maps, path.clone(), - &mut self.usage_tracker, + self.usage_tracker, &mut Some(&mut references), ); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 347bf90f849..9917207d217 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -353,6 +353,7 @@ impl DefCollector { let resolved_import = resolve_import( crate_id, &collected_import, + &context.def_interner, &context.def_maps, &mut context.usage_tracker, &mut Some(&mut references), @@ -375,6 +376,7 @@ impl DefCollector { resolve_import( crate_id, &collected_import, + &context.def_interner, &context.def_maps, &mut context.usage_tracker, &mut None, @@ -557,6 +559,7 @@ fn inject_prelude( }; if let Ok(PathResolution { item, errors }) = path_resolver::resolve_path( + &context.def_interner, &context.def_maps, ModuleId { krate: crate_id, local_id: crate_root }, None, diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 56b397d079e..d11879bdffa 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -1196,6 +1196,7 @@ pub(crate) fn collect_trait_impl_items( (unresolved_functions, associated_types, associated_constants) } +#[allow(clippy::too_many_arguments)] pub(crate) fn collect_global( interner: &mut NodeInterner, def_map: &mut CrateDefMap, diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index 58a3a841801..32670e0d77a 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -4,8 +4,11 @@ use thiserror::Error; use crate::graph::CrateId; use crate::hir::def_collector::dc_crate::CompilationError; -use crate::node_interner::{FuncId, GlobalId, ReferenceId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{ + FuncId, GlobalId, NodeInterner, ReferenceId, StructId, TraitId, TypeAliasId, +}; use crate::usage_tracker::UsageTracker; +use crate::Type; use std::collections::BTreeMap; @@ -100,6 +103,7 @@ pub struct Turbofish { enum IntermediatePathResolutionItem { Module(ModuleId), Struct(StructId, Option), + TypeAlias(TypeAliasId, Option), Trait(TraitId, Option), } @@ -162,6 +166,7 @@ impl<'a> From<&'a PathResolutionError> for CustomDiagnostic { pub fn resolve_import( crate_id: CrateId, import_directive: &ImportDirective, + interner: &NodeInterner, def_maps: &BTreeMap, usage_tracker: &mut UsageTracker, path_references: &mut Option<&mut Vec>, @@ -176,6 +181,7 @@ pub fn resolve_import( import_directive, crate_id, crate_id, + interner, def_maps, usage_tracker, path_references, @@ -215,6 +221,7 @@ fn resolve_path_to_ns( import_directive: &ImportDirective, crate_id: CrateId, importing_crate: CrateId, + interner: &NodeInterner, def_maps: &BTreeMap, usage_tracker: &mut UsageTracker, path_references: &mut Option<&mut Vec>, @@ -228,6 +235,7 @@ fn resolve_path_to_ns( crate_id, importing_crate, import_path, + interner, def_maps, usage_tracker, path_references, @@ -242,6 +250,7 @@ fn resolve_path_to_ns( importing_crate, import_path, import_directive.module_id, + interner, def_maps, true, // plain or crate usage_tracker, @@ -260,6 +269,7 @@ fn resolve_path_to_ns( crate_id, // def_map, import_directive, + interner, def_maps, usage_tracker, path_references, @@ -272,6 +282,7 @@ fn resolve_path_to_ns( importing_crate, import_path, import_directive.module_id, + interner, def_maps, true, // plain or crate usage_tracker, @@ -282,6 +293,7 @@ fn resolve_path_to_ns( crate::ast::PathKind::Dep => resolve_external_dep( crate_id, import_directive, + interner, def_maps, usage_tracker, path_references, @@ -297,6 +309,7 @@ fn resolve_path_to_ns( importing_crate, import_path, parent_module_id, + interner, def_maps, false, // plain or crate usage_tracker, @@ -314,8 +327,8 @@ fn resolve_path_to_ns( fn resolve_path_from_crate_root( crate_id: CrateId, importing_crate: CrateId, - import_path: &[PathSegment], + interner: &NodeInterner, def_maps: &BTreeMap, usage_tracker: &mut UsageTracker, path_references: &mut Option<&mut Vec>, @@ -326,6 +339,7 @@ fn resolve_path_from_crate_root( importing_crate, import_path, starting_mod, + interner, def_maps, true, // plain or crate usage_tracker, @@ -339,6 +353,7 @@ fn resolve_name_in_module( importing_crate: CrateId, import_path: &[PathSegment], starting_mod: LocalModuleId, + interner: &NodeInterner, def_maps: &BTreeMap, plain_or_crate: bool, usage_tracker: &mut UsageTracker, @@ -416,7 +431,31 @@ fn resolve_name_in_module( ), ) } - ModuleDefId::TypeAliasId(_) => panic!("type aliases cannot be used in type namespace"), + ModuleDefId::TypeAliasId(id) => { + if let Some(path_references) = path_references { + path_references.push(ReferenceId::Alias(id)); + } + + let type_alias = interner.get_type_alias(id); + let type_alias = type_alias.borrow(); + + let module_id = if let Type::Struct(struct_id, _generics) = &type_alias.typ { + struct_id.borrow().id.module_id() + } else { + todo!("Type alias in path not pointing to a struct") + }; + + ( + module_id, + IntermediatePathResolutionItem::TypeAlias( + id, + last_segment_generics.as_ref().map(|generics| Turbofish { + generics: generics.clone(), + span: last_segment.turbofish_span(), + }), + ), + ) + } ModuleDefId::TraitId(id) => { if let Some(path_references) = path_references { path_references.push(ReferenceId::Trait(id)); @@ -485,6 +524,7 @@ fn resolve_path_name(import_directive: &ImportDirective) -> Ident { fn resolve_external_dep( crate_id: CrateId, directive: &ImportDirective, + interner: &NodeInterner, def_maps: &BTreeMap, usage_tracker: &mut UsageTracker, path_references: &mut Option<&mut Vec>, @@ -529,6 +569,7 @@ fn resolve_external_dep( &dep_directive, dep_module.krate, importing_crate, + interner, def_maps, usage_tracker, path_references, @@ -552,6 +593,9 @@ fn merge_intermediate_path_resolution_item_with_module_def_id( IntermediatePathResolutionItem::Struct(struct_id, generics) => { PathResolutionItem::StructFunction(struct_id, generics, func_id) } + IntermediatePathResolutionItem::TypeAlias(alias_id, generics) => { + PathResolutionItem::TypeAliasFunction(alias_id, generics, func_id) + } IntermediatePathResolutionItem::Trait(trait_id, generics) => { PathResolutionItem::TraitFunction(trait_id, generics, func_id) } diff --git a/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs b/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs index 705820e9101..98d4aee3f5c 100644 --- a/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs +++ b/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs @@ -1,6 +1,6 @@ use super::import::{resolve_import, ImportDirective, PathResolution, PathResolutionResult}; use crate::ast::{ItemVisibility, Path}; -use crate::node_interner::ReferenceId; +use crate::node_interner::{NodeInterner, ReferenceId}; use crate::usage_tracker::UsageTracker; use std::collections::BTreeMap; @@ -15,6 +15,7 @@ pub trait PathResolver { /// a module or type). fn resolve( &self, + interner: &NodeInterner, def_maps: &BTreeMap, path: Path, usage_tracker: &mut UsageTracker, @@ -42,12 +43,14 @@ impl StandardPathResolver { impl PathResolver for StandardPathResolver { fn resolve( &self, + interner: &NodeInterner, def_maps: &BTreeMap, path: Path, usage_tracker: &mut UsageTracker, path_references: &mut Option<&mut Vec>, ) -> PathResolutionResult { resolve_path( + interner, def_maps, self.module_id, self.self_type_module_id, @@ -69,6 +72,7 @@ impl PathResolver for StandardPathResolver { /// Resolve the given path to a function or a type. /// In the case of a conflict, functions are given priority pub fn resolve_path( + interner: &NodeInterner, def_maps: &BTreeMap, module_id: ModuleId, self_type_module_id: Option, @@ -85,8 +89,14 @@ pub fn resolve_path( alias: None, is_prelude: false, }; - let resolved_import = - resolve_import(module_id.krate, &import, def_maps, usage_tracker, path_references)?; + let resolved_import = resolve_import( + module_id.krate, + &import, + interner, + def_maps, + usage_tracker, + path_references, + )?; Ok(PathResolution { item: resolved_import.item, errors: resolved_import.errors }) } diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 7873d9d1755..1c5775985df 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -3570,15 +3570,19 @@ fn use_type_alias_in_method_call() { } impl Foo { - fn new() { + fn new() -> Self { Foo {} } } type Bar = Foo; + fn foo() -> Foo { + Bar::new() + } + fn main() { - Bar::new(); + let _ = foo(); } "#; assert_no_errors(src); diff --git a/tooling/lsp/src/attribute_reference_finder.rs b/tooling/lsp/src/attribute_reference_finder.rs index 22afa086303..660ee8ffdfb 100644 --- a/tooling/lsp/src/attribute_reference_finder.rs +++ b/tooling/lsp/src/attribute_reference_finder.rs @@ -18,7 +18,7 @@ use noirc_frontend::{ path_resolver::{PathResolver, StandardPathResolver}, }, }, - node_interner::ReferenceId, + node_interner::{NodeInterner, ReferenceId}, parser::{ParsedSubModule, Parser}, token::CustomAttribute, usage_tracker::UsageTracker, @@ -30,6 +30,7 @@ pub(crate) struct AttributeReferenceFinder<'a> { /// The module ID in scope. This might change as we traverse the AST /// if we are analyzing something inside an inline module declaration. module_id: ModuleId, + interner: &'a NodeInterner, def_maps: &'a BTreeMap, reference_id: Option, } @@ -40,6 +41,7 @@ impl<'a> AttributeReferenceFinder<'a> { file: FileId, byte_index: usize, krate: CrateId, + interner: &'a NodeInterner, def_maps: &'a BTreeMap, ) -> Self { // Find the module the current file belongs to @@ -52,7 +54,7 @@ impl<'a> AttributeReferenceFinder<'a> { def_map.root() }; let module_id = ModuleId { krate, local_id }; - Self { byte_index, module_id, def_maps, reference_id: None } + Self { byte_index, module_id, interner, def_maps, reference_id: None } } pub(crate) fn find(&mut self, parsed_module: &ParsedModule) -> Option { @@ -102,7 +104,8 @@ impl<'a> Visitor for AttributeReferenceFinder<'a> { let resolver = StandardPathResolver::new(self.module_id, None); let mut usage_tracker = UsageTracker::default(); - let Ok(result) = resolver.resolve(self.def_maps, path, &mut usage_tracker, &mut None) + let Ok(result) = + resolver.resolve(self.interner, self.def_maps, path, &mut usage_tracker, &mut None) else { return; }; diff --git a/tooling/lsp/src/requests/goto_definition.rs b/tooling/lsp/src/requests/goto_definition.rs index a2443ea165d..9380209da5c 100644 --- a/tooling/lsp/src/requests/goto_definition.rs +++ b/tooling/lsp/src/requests/goto_definition.rs @@ -46,6 +46,7 @@ fn on_goto_definition_inner( file_id, byte_index, args.crate_id, + args.interner, args.def_maps, ); finder.find(&parsed_module) diff --git a/tooling/lsp/src/requests/hover.rs b/tooling/lsp/src/requests/hover.rs index 64974a42133..eb066b53b78 100644 --- a/tooling/lsp/src/requests/hover.rs +++ b/tooling/lsp/src/requests/hover.rs @@ -47,6 +47,7 @@ pub(crate) fn on_hover_request( file_id, byte_index, args.crate_id, + args.interner, args.def_maps, ); finder.find(&parsed_module) From 65f31f2075178e6c67edce9622aab69d1eaf8485 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 29 Oct 2024 16:05:58 -0300 Subject: [PATCH 3/5] Clippy --- compiler/noirc_frontend/src/elaborator/comptime.rs | 6 +++--- compiler/noirc_frontend/src/elaborator/scope.rs | 2 +- compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index e7645fdfcb9..13f51abe6ba 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -413,7 +413,7 @@ impl<'context> Elaborator<'context> { if let Some(id) = dc_mod::collect_function( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), - &mut self.usage_tracker, + self.usage_tracker, &function, module_id, self.file, @@ -463,7 +463,7 @@ impl<'context> Elaborator<'context> { let (global, error) = dc_mod::collect_global( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), - &mut self.usage_tracker, + self.usage_tracker, Documented::new(global, item.doc_comments), visibility, self.file, @@ -480,7 +480,7 @@ impl<'context> Elaborator<'context> { if let Some((type_id, the_struct)) = dc_mod::collect_struct( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), - &mut self.usage_tracker, + self.usage_tracker, Documented::new(struct_def, item.doc_comments), self.file, self.local_module, diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index ccba14ccd5b..33e97c1df22 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -90,7 +90,7 @@ impl<'context> Elaborator<'context> { self.interner, self.def_maps, path, - &mut self.usage_tracker, + self.usage_tracker, &mut None, ); } diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index d11879bdffa..94c091f9791 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -900,6 +900,7 @@ fn push_child_module( Ok(mod_id) } +#[allow(clippy::too_many_arguments)] pub fn collect_function( interner: &mut NodeInterner, def_map: &mut CrateDefMap, @@ -954,6 +955,7 @@ pub fn collect_function( Some(func_id) } +#[allow(clippy::too_many_arguments)] pub fn collect_struct( interner: &mut NodeInterner, def_map: &mut CrateDefMap, From 0374bbacc2a29dd400bfce8e607bf5940b334c66 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Tue, 29 Oct 2024 16:25:56 -0300 Subject: [PATCH 4/5] Solve type alias generics in path --- .../noirc_frontend/src/elaborator/patterns.rs | 42 +++++++++++-- .../noirc_frontend/src/tests/turbofish.rs | 60 +++++++++++++++++++ 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index b45f455633b..543f3055bee 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -17,7 +17,7 @@ use crate::{ stmt::HirPattern, }, node_interner::{DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, TraitImplKind}, - Kind, ResolvedGeneric, Shared, StructType, Type, TypeBindings, + Kind, ResolvedGeneric, Shared, StructType, Type, TypeAlias, TypeBindings, }; use super::{Elaborator, ResolverMeta}; @@ -453,6 +453,30 @@ impl<'context> Elaborator<'context> { self.resolve_turbofish_generics(&struct_type.generics, turbofish_generics) } + pub(super) fn resolve_alias_turbofish_generics( + &mut self, + type_alias: &TypeAlias, + generics: Vec, + unresolved_turbofish: Option>, + span: Span, + ) -> Vec { + let Some(turbofish_generics) = unresolved_turbofish else { + return generics; + }; + + if turbofish_generics.len() != generics.len() { + self.push_err(TypeCheckError::GenericCountMismatch { + item: format!("alias {}", type_alias.name), + expected: generics.len(), + found: turbofish_generics.len(), + span, + }); + return generics; + } + + self.resolve_turbofish_generics(&type_alias.generics, turbofish_generics) + } + pub(super) fn resolve_turbofish_generics( &mut self, generics: &[ResolvedGeneric], @@ -526,10 +550,18 @@ impl<'context> Elaborator<'context> { generics.span, ) } - PathResolutionItem::TypeAliasFunction(_type_alias_id, Some(generics), _func_id) => { - // TODO: https://github.com/noir-lang/noir/issues/6311 - self.push_err(TypeCheckError::UnsupportedTurbofishUsage { span: generics.span }); - Vec::new() + PathResolutionItem::TypeAliasFunction(type_alias_id, Some(generics), _func_id) => { + let type_alias = self.interner.get_type_alias(type_alias_id); + let type_alias = type_alias.borrow(); + let alias_generics = vecmap(&type_alias.generics, |generic| { + self.interner.next_type_variable_with_kind(generic.kind()) + }); + self.resolve_alias_turbofish_generics( + &type_alias, + alias_generics, + Some(generics.generics), + generics.span, + ) } PathResolutionItem::TraitFunction(_trait_id, Some(generics), _func_id) => { // TODO: https://github.com/noir-lang/noir/issues/6310 diff --git a/compiler/noirc_frontend/src/tests/turbofish.rs b/compiler/noirc_frontend/src/tests/turbofish.rs index 3ded243a280..d9461f64f16 100644 --- a/compiler/noirc_frontend/src/tests/turbofish.rs +++ b/compiler/noirc_frontend/src/tests/turbofish.rs @@ -269,3 +269,63 @@ fn turbofish_in_type_before_call_errors() { assert_eq!(expected_typ, "i32"); assert_eq!(expr_typ, "bool"); } + +#[test] +fn use_generic_type_alias_with_turbofish_in_method_call_does_not_error() { + let src = r#" + pub struct Foo { + } + + impl Foo { + fn new() -> Self { + Foo {} + } + } + + type Bar = Foo; + + fn foo() -> Foo { + Bar::::new() + } + + fn main() { + let _ = foo(); + } + "#; + assert_no_errors(src); +} + +#[test] +fn use_generic_type_alias_with_turbofish_in_method_call_errors() { + let src = r#" + pub struct Foo { + x: T, + } + + impl Foo { + fn new(x: T) -> Self { + Foo { x } + } + } + + type Bar = Foo; + + fn main() { + let _ = Bar::::new(true); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); + + let CompilationError::TypeError(TypeCheckError::TypeMismatch { + expected_typ, + expr_typ, + expr_span: _, + }) = &errors[0].0 + else { + panic!("Expected a type mismatch error, got {:?}", errors[0].0); + }; + + assert_eq!(expected_typ, "i32"); + assert_eq!(expr_typ, "bool"); +} From d2e9ba9685a1d24abd92ae7c501788fa2c02c25b Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 30 Oct 2024 07:54:48 -0300 Subject: [PATCH 5/5] Resolve turbofish for alias in path --- .../noirc_frontend/src/elaborator/patterns.rs | 32 +++++++-- .../src/hir/resolution/import.rs | 14 ++-- compiler/noirc_frontend/src/tests.rs | 26 +++++++ .../noirc_frontend/src/tests/turbofish.rs | 71 +++++++++++++++++++ 4 files changed, 132 insertions(+), 11 deletions(-) diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 543f3055bee..978b86e68e8 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -550,18 +550,36 @@ impl<'context> Elaborator<'context> { generics.span, ) } - PathResolutionItem::TypeAliasFunction(type_alias_id, Some(generics), _func_id) => { + PathResolutionItem::TypeAliasFunction(type_alias_id, generics, _func_id) => { let type_alias = self.interner.get_type_alias(type_alias_id); let type_alias = type_alias.borrow(); let alias_generics = vecmap(&type_alias.generics, |generic| { self.interner.next_type_variable_with_kind(generic.kind()) }); - self.resolve_alias_turbofish_generics( - &type_alias, - alias_generics, - Some(generics.generics), - generics.span, - ) + + // First solve the generics on the alias, if any + let generics = if let Some(generics) = generics { + self.resolve_alias_turbofish_generics( + &type_alias, + alias_generics, + Some(generics.generics), + generics.span, + ) + } else { + alias_generics + }; + + // Now instantiate the underlying struct with those generics, the struct might + // have more generics than those in the alias, like in this example: + // + // type Alias = Struct; + let typ = type_alias.get_type(&generics); + let Type::Struct(_, generics) = typ else { + // See https://github.com/noir-lang/noir/issues/6398 + panic!("Expected type alias to point to struct") + }; + + generics } PathResolutionItem::TraitFunction(_trait_id, Some(generics), _func_id) => { // TODO: https://github.com/noir-lang/noir/issues/6310 diff --git a/compiler/noirc_frontend/src/hir/resolution/import.rs b/compiler/noirc_frontend/src/hir/resolution/import.rs index 32670e0d77a..7afb056cbaf 100644 --- a/compiler/noirc_frontend/src/hir/resolution/import.rs +++ b/compiler/noirc_frontend/src/hir/resolution/import.rs @@ -439,10 +439,16 @@ fn resolve_name_in_module( let type_alias = interner.get_type_alias(id); let type_alias = type_alias.borrow(); - let module_id = if let Type::Struct(struct_id, _generics) = &type_alias.typ { - struct_id.borrow().id.module_id() - } else { - todo!("Type alias in path not pointing to a struct") + let module_id = match &type_alias.typ { + Type::Struct(struct_id, _generics) => struct_id.borrow().id.module_id(), + Type::Error => { + return Err(PathResolutionError::Unresolved(last_ident.clone())); + } + _ => { + // For now we only allow type aliases that point to structs. + // The more general case is captured here: https://github.com/noir-lang/noir/issues/6398 + panic!("Type alias in path not pointing to struct not yet supported") + } }; ( diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 1c5775985df..edbc5fca2e3 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -3587,3 +3587,29 @@ fn use_type_alias_in_method_call() { "#; assert_no_errors(src); } + +#[test] +fn use_type_alias_to_generic_concrete_type_in_method_call() { + let src = r#" + pub struct Foo { + x: T, + } + + impl Foo { + fn new(x: T) -> Self { + Foo { x } + } + } + + type Bar = Foo; + + fn foo() -> Bar { + Bar::new(1) + } + + fn main() { + let _ = foo(); + } + "#; + assert_no_errors(src); +} diff --git a/compiler/noirc_frontend/src/tests/turbofish.rs b/compiler/noirc_frontend/src/tests/turbofish.rs index d9461f64f16..3bde3e17c80 100644 --- a/compiler/noirc_frontend/src/tests/turbofish.rs +++ b/compiler/noirc_frontend/src/tests/turbofish.rs @@ -329,3 +329,74 @@ fn use_generic_type_alias_with_turbofish_in_method_call_errors() { assert_eq!(expected_typ, "i32"); assert_eq!(expr_typ, "bool"); } + +#[test] +fn use_generic_type_alias_with_partial_generics_with_turbofish_in_method_call_does_not_error() { + let src = r#" + pub struct Foo { + x: T, + y: U, + } + + impl Foo { + fn new(x: T, y: U) -> Self { + Foo { x, y } + } + } + + type Bar = Foo; + + fn main() { + let _ = Bar::::new(true, 1); + } + "#; + assert_no_errors(src); +} + +#[test] +fn use_generic_type_alias_with_partial_generics_with_turbofish_in_method_call_errors_first_type() { + let src = r#" + pub struct Foo { + x: T, + y: U, + } + + impl Foo { + fn new(x: T, y: U) -> Self { + Foo { x, y } + } + } + + type Bar = Foo; + + fn main() { + let _ = Bar::::new(1, 1); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); +} + +#[test] +fn use_generic_type_alias_with_partial_generics_with_turbofish_in_method_call_errors_second_type() { + let src = r#" + pub struct Foo { + x: T, + y: U, + } + + impl Foo { + fn new(x: T, y: U) -> Self { + Foo { x, y } + } + } + + type Bar = Foo; + + fn main() { + let _ = Bar::::new(true, true); + } + "#; + let errors = get_program_errors(src); + assert_eq!(errors.len(), 1); +}