diff --git a/base/src/symbol.rs b/base/src/symbol.rs index f3e545bf86..05b72c4e61 100644 --- a/base/src/symbol.rs +++ b/base/src/symbol.rs @@ -109,6 +109,18 @@ impl PartialEq for Symbol { } } +impl PartialEq for Symbol { + fn eq(&self, other: &SymbolRef) -> bool { + **self == *other + } +} + +impl PartialEq for SymbolRef { + fn eq(&self, other: &Symbol) -> bool { + *self == **other + } +} + impl PartialOrd for Symbol { fn partial_cmp(&self, other: &Symbol) -> Option { (**self).partial_cmp(other) diff --git a/completion/src/lib.rs b/completion/src/lib.rs index b8107eb1d7..a2e1860de9 100644 --- a/completion/src/lib.rs +++ b/completion/src/lib.rs @@ -788,19 +788,19 @@ where } } -pub trait Extract: Sized { +pub trait Extract<'a>: Sized { type Output; - fn extract(self, found: &Found) -> Result; - fn match_extract(self, match_: &Match) -> Result; + fn extract(self, found: &Found<'a>) -> Result; + fn match_extract(self, match_: &Match<'a>) -> Result; } #[derive(Clone, Copy)] pub struct TypeAt<'a> { pub env: &'a TypeEnv, } -impl<'a> Extract for TypeAt<'a> { +impl<'a> Extract<'a> for TypeAt<'a> { type Output = Either; - fn extract(self, found: &Found) -> Result { + fn extract(self, found: &Found<'a>) -> Result { match found.match_ { Some(ref match_) => self.match_extract(match_), None => self.match_extract(found.enclosing_match()), @@ -825,30 +825,31 @@ impl<'a> Extract for TypeAt<'a> { #[derive(Clone, Copy)] pub struct IdentAt; -impl Extract for IdentAt { - type Output = Symbol; - fn extract(self, found: &Found) -> Result { +impl<'a> Extract<'a> for IdentAt { + type Output = &'a SymbolRef; + fn extract(self, found: &Found<'a>) -> Result { match found.match_ { Some(ref match_) => self.match_extract(match_), None => self.match_extract(found.enclosing_match()), } } - fn match_extract(self, found: &Match) -> Result { - Ok(match *found { - Match::Expr(&Spanned { - value: Expr::Ident(ref id), + fn match_extract(self, found: &Match<'a>) -> Result { + Ok(match found { + Match::Expr(Spanned { + value: Expr::Ident(id), .. }) - | Match::Pattern(&Spanned { - value: Pattern::Ident(ref id), + | Match::Pattern(Spanned { + value: Pattern::Ident(id), .. - }) => id.name.clone(), - Match::Ident(_, id, _) => id.clone(), - Match::Pattern(&Spanned { - value: Pattern::As(ref id, _), + }) => &id.name, + Match::Ident(_, id, _) => id, + Match::Pattern(Spanned { + value: Pattern::As(id, _), .. - }) => id.value.clone(), + }) => &id.value, + Match::Type(_, id, _) => id, _ => return Err(()), }) } @@ -856,7 +857,7 @@ impl Extract for IdentAt { #[derive(Copy, Clone)] pub struct SpanAt; -impl Extract for SpanAt { +impl<'a> Extract<'a> for SpanAt { type Output = Span; fn extract(self, found: &Found) -> Result { match found.match_ { @@ -882,13 +883,13 @@ macro_rules! tuple_extract { macro_rules! tuple_extract_ { ($($id: ident)*) => { #[allow(non_snake_case)] - impl<$($id : Extract),*> Extract for ( $($id),* ) { + impl<'a, $($id : Extract<'a>),*> Extract<'a> for ( $($id),* ) { type Output = ( $($id::Output),* ); - fn extract(self, found: &Found) -> Result { + fn extract(self, found: &Found<'a>) -> Result { let ( $($id),* ) = self; Ok(( $( $id.extract(found)? ),* )) } - fn match_extract(self, found: &Match) -> Result { + fn match_extract(self, found: &Match<'a>) -> Result { let ( $($id),* ) = self; Ok(( $( $id.match_extract(found)? ),* )) } @@ -898,14 +899,14 @@ macro_rules! tuple_extract_ { tuple_extract! {A B C D E F G H} -pub fn completion( +pub fn completion<'a, T>( extract: T, source_span: Span, - expr: &SpannedExpr, + expr: &'a SpannedExpr, pos: BytePos, ) -> Result where - T: Extract, + T: Extract<'a>, { let found = complete_at((), source_span, expr, pos)?; extract.extract(&found) @@ -931,16 +932,16 @@ pub fn find_all_symbols( ) -> Result<(String, Vec>), ()> { let extract = IdentAt; completion(extract, source_span, expr, pos).map(|symbol| { - struct ExtractIdents { + struct ExtractIdents<'b> { result: Vec>, - symbol: Symbol, + symbol: &'b SymbolRef, } - impl<'a> Visitor<'a> for ExtractIdents { + impl<'a, 'b> Visitor<'a> for ExtractIdents<'b> { type Ident = Symbol; fn visit_expr(&mut self, e: &'a SpannedExpr) { match e.value { - Expr::Ident(ref id) if id.name == self.symbol => { + Expr::Ident(ref id) if id.name == *self.symbol => { self.result.push(e.span); } _ => walk_expr(self, e), @@ -949,11 +950,11 @@ pub fn find_all_symbols( fn visit_pattern(&mut self, p: &'a SpannedPattern) { match p.value { - Pattern::As(ref id, ref pat) if id.value == self.symbol => { + Pattern::As(ref id, ref pat) if id.value == *self.symbol => { self.result.push(p.span); walk_pattern(self, &pat.value); } - Pattern::Ident(ref id) if id.name == self.symbol => { + Pattern::Ident(ref id) if id.name == *self.symbol => { self.result.push(p.span); } _ => walk_pattern(self, &p.value), @@ -973,7 +974,7 @@ pub fn symbol( source_span: Span, expr: &SpannedExpr, pos: BytePos, -) -> Result { +) -> Result<&SymbolRef, ()> { let extract = IdentAt; completion(extract, source_span, expr, pos) } @@ -1019,7 +1020,11 @@ pub fn all_symbols( pos::spanned( bind.name.span, CompletionSymbol { - name: &bind.name.value, + name: bind + .finalized_alias + .as_ref() + .map(|alias| &alias.name) + .unwrap_or(&bind.name.value), content: CompletionSymbolContent::Type { alias: &bind.alias.value, }, diff --git a/completion/tests/completion.rs b/completion/tests/completion.rs index 48b9686e91..6968c2d5fa 100644 --- a/completion/tests/completion.rs +++ b/completion/tests/completion.rs @@ -8,12 +8,13 @@ extern crate gluon_check as check; extern crate gluon_completion as completion; extern crate gluon_parser as parser; -use crate::base::ast::Argument; -use crate::base::kind::{ArcKind, Kind}; -use crate::base::metadata::Metadata; -use crate::base::metadata::{Comment, CommentType}; -use crate::base::pos::{BytePos, Span}; -use crate::base::types::{ArcType, Field, Type}; +use crate::base::{ + ast::Argument, + kind::{ArcKind, Kind}, + metadata::{Comment, CommentType, Metadata}, + pos::{BytePos, Span}, + types::{ArcType, Field, Type}, +}; use either::Either; @@ -61,6 +62,13 @@ fn find_type_loc(s: &str, line: usize, column: usize) -> Result { find_span_type(s, pos).map(|t| t.1.right().expect("Type")) } +fn symbol(s: &str, pos: BytePos) -> Result { + let (expr, result) = support::typecheck_expr(s); + assert!(result.is_ok(), "{}", result.unwrap_err()); + + completion::symbol(expr.span, &expr, pos).map(|s| s.declared_name().to_string()) +} + fn get_metadata(s: &str, pos: BytePos) -> Option { let env = MockEnv::new(); @@ -609,3 +617,17 @@ let f x : Int -> Int = x assert_eq!(result, expected); } + +#[test] +fn type_symbol() { + let _ = env_logger::try_init(); + + let text = r#" +type Test a = | Test a +let x : Test Int = Test 1 +1.0 +"#; + let result = symbol(text, loc(text, 2, 10)); + + assert_eq!(result, Ok("Test".into())); +}