Skip to content

Commit

Permalink
Merge dddb7d4 into 5b27ea4
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Sep 20, 2024
2 parents 5b27ea4 + dddb7d4 commit d0f5229
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 18 deletions.
16 changes: 13 additions & 3 deletions compiler/noirc_frontend/src/parser/parser/path.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::ast::{AsTraitPath, Path, PathKind, PathSegment, TypePath, UnresolvedType};
use crate::ast::{AsTraitPath, Ident, Path, PathKind, PathSegment, TypePath, UnresolvedType};
use crate::macros_api::ExpressionKind;
use crate::parser::{NoirParser, ParserError, ParserErrorReason};

use crate::token::{Keyword, Token};

use chumsky::prelude::*;
use noirc_errors::Span;

use super::keyword;
use super::primitives::{ident, path_segment, path_segment_no_turbofish, turbofish};
Expand Down Expand Up @@ -78,10 +79,19 @@ pub(super) fn type_path<'a>(
) -> impl NoirParser<ExpressionKind> + 'a {
primitive_type()
.then_ignore(just(Token::DoubleColon))
.then(ident())
.then(ident().or_not())
.then(turbofish(type_parser))
.map(|((typ, item), turbofish)| {
.validate(|((typ, item), turbofish), span, emit| {
let turbofish = turbofish.unwrap_or_default();
let item = if let Some(item) = item {
item
} else {
emit(ParserError::with_reason(
ParserErrorReason::ExpectedIdentifierAfterColons,
span,
));
Ident::new(String::new(), Span::from(span.end()..span.end()))
};
ExpressionKind::TypePath(TypePath { typ, item, turbofish })
})
}
Expand Down
61 changes: 55 additions & 6 deletions tooling/lsp/src/requests/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ use noirc_frontend::{
ast::{
AsTraitPath, AttributeTarget, BlockExpression, CallExpression, ConstructorExpression,
Expression, ExpressionKind, ForLoopStatement, GenericTypeArgs, Ident, IfExpression,
ItemVisibility, LValue, Lambda, LetStatement, MemberAccessExpression, MethodCallExpression,
NoirFunction, NoirStruct, NoirTraitImpl, Path, PathKind, Pattern, Statement,
TraitImplItemKind, TypeImpl, UnresolvedGeneric, UnresolvedGenerics, UnresolvedType,
UnresolvedTypeData, UseTree, UseTreeKind, Visitor,
IntegerBitSize, ItemVisibility, LValue, Lambda, LetStatement, MemberAccessExpression,
MethodCallExpression, NoirFunction, NoirStruct, NoirTraitImpl, Path, PathKind, Pattern,
Signedness, Statement, TraitImplItemKind, TypeImpl, TypePath, UnresolvedGeneric,
UnresolvedGenerics, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, UseTree,
UseTreeKind, Visitor,
},
graph::{CrateId, Dependency},
hir::def_map::{CrateDefMap, LocalModuleId, ModuleId},
Expand All @@ -29,7 +30,7 @@ use noirc_frontend::{
node_interner::ReferenceId,
parser::{Item, ItemKind, ParsedSubModule},
token::{CustomAttribute, Token, Tokens},
ParsedModule, StructType, Type, TypeBinding,
Kind, ParsedModule, StructType, Type, TypeBinding,
};
use sort_text::underscore_sort_text;

Expand Down Expand Up @@ -362,6 +363,8 @@ impl<'a> NodeFinder<'a> {
self.local_variables_completion(&prefix);
self.builtin_functions_completion(&prefix, function_completion_kind);
self.builtin_values_completion(&prefix);
self.builtin_types_completion(&prefix);
self.type_parameters_completion(&prefix);
if let Some(self_type) = &self.self_type {
let self_prefix = true;
self.complete_type_fields_and_methods(
Expand Down Expand Up @@ -627,7 +630,15 @@ impl<'a> NodeFinder<'a> {
};

for (name, methods) in methods_by_name {
for (func_id, _method_type) in methods.iter() {
for (func_id, method_type) in methods.iter() {
if function_kind == FunctionKind::Any {
if let Some(method_type) = method_type {
if method_type.unify(typ).is_err() {
continue;
}
}
}

if name_matches(name, prefix) {
let completion_items = self.function_completion_items(
name,
Expand Down Expand Up @@ -1553,6 +1564,44 @@ impl<'a> Visitor for NodeFinder<'a> {
false
}

fn visit_type_path(&mut self, type_path: &TypePath, _: Span) -> bool {
if type_path.item.span().end() as usize != self.byte_index {
return true;
}

let typ = match &type_path.typ.typ {
UnresolvedTypeData::FieldElement => Some(Type::FieldElement),
UnresolvedTypeData::Integer(signedness, integer_bit_size) => {
Some(Type::Integer(*signedness, *integer_bit_size))
}
UnresolvedTypeData::Bool => Some(Type::Bool),
UnresolvedTypeData::String(UnresolvedTypeExpression::Constant(value, _)) => {
Some(Type::String(Box::new(Type::Constant(
*value,
Kind::Numeric(Box::new(Type::Integer(
Signedness::Unsigned,
IntegerBitSize::ThirtyTwo,
))),
))))
}
UnresolvedTypeData::Quoted(quoted_type) => Some(Type::Quoted(*quoted_type)),
_ => None,
};

if let Some(typ) = typ {
let prefix = &type_path.item.0.contents;
self.complete_type_methods(
&typ,
prefix,
FunctionKind::Any,
FunctionCompletionKind::NameAndParameters,
false, // self_prefix
);
}

false
}

fn visit_custom_attribute(&mut self, attribute: &CustomAttribute, target: AttributeTarget) {
if self.byte_index != attribute.contents_span.end() as usize {
return;
Expand Down
47 changes: 38 additions & 9 deletions tooling/lsp/src/requests/completion/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,27 @@ mod completion_tests {
.await;
}

#[test]
async fn test_complete_type_path_with_non_empty_name() {
let src = r#"
trait One {
fn one() -> Self;
}
impl One for Field {
fn one() -> Self {
1
}
}
fn main() {
Field::o>|<
}
"#;
assert_completion(src, vec![function_completion_item("one()", "one()", "fn() -> Field")])
.await;
}

#[test]
async fn test_complete_function_without_arguments() {
let src = r#"
Expand Down Expand Up @@ -756,22 +777,30 @@ mod completion_tests {
);
}

#[test]
async fn test_suggest_builtin_types_in_any_position() {
let src = r#"
fn foo() {
i>|<
}
"#;

let items = get_completions(src).await;
assert!(items.iter().any(|item| item.label == "i8"));
}

#[test]
async fn test_suggest_true() {
let src = r#"
fn main() {
let x = t>|<
}
"#;
assert_completion_excluding_auto_import(
src,
vec![simple_completion_item(
"true",
CompletionItemKind::KEYWORD,
Some("bool".to_string()),
)],
)
.await;

let items = get_completions(src).await;
assert!(items
.iter()
.any(|item| item.label == "true" && item.kind == Some(CompletionItemKind::KEYWORD)));
}

#[test]
Expand Down

0 comments on commit d0f5229

Please sign in to comment.