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

Context completion #1584

Merged
merged 5 commits into from
Sep 21, 2023
Merged
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
111 changes: 81 additions & 30 deletions core/src/term/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,12 @@ impl Traverse<RichTerm> for RuntimeContract {
Ok(RuntimeContract { contract, ..self })
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&RichTerm) -> TraverseControl<U>) -> Option<U> {
self.contract.traverse_ref(f)
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&RichTerm, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
self.contract.traverse_ref(f, state)
}
}

Expand Down Expand Up @@ -478,8 +482,12 @@ impl Traverse<RichTerm> for LabeledType {
typ.traverse(f, order).map(|typ| LabeledType { typ, label })
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&RichTerm) -> TraverseControl<U>) -> Option<U> {
self.typ.traverse_ref(f)
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&RichTerm, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
self.typ.traverse_ref(f, state)
}
}

Expand Down Expand Up @@ -592,11 +600,15 @@ impl Traverse<RichTerm> for TypeAnnotation {
Ok(TypeAnnotation { typ, contracts })
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&RichTerm) -> TraverseControl<U>) -> Option<U> {
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&RichTerm, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
self.contracts
.iter()
.find_map(|c| c.traverse_ref(f))
.or_else(|| self.typ.as_ref().and_then(|t| t.traverse_ref(f)))
.find_map(|c| c.traverse_ref(f, state))
.or_else(|| self.typ.as_ref().and_then(|t| t.traverse_ref(f, state)))
}
}

Expand Down Expand Up @@ -1625,8 +1637,14 @@ impl RichTerm {
}

/// Flow control for tree traverals.
pub enum TraverseControl<U> {
pub enum TraverseControl<S, U> {
/// Normal control flow: continue recursing into the children.
///
/// Pass the state &S to all children.
ContinueWithScope(S),
/// Normal control flow: continue recursing into the children.
///
/// The state that was passed to the parent will be re-used for the children.
Continue,

/// Skip this branch of the tree.
Expand All @@ -1636,7 +1654,7 @@ pub enum TraverseControl<U> {
Return(U),
}

impl<U> From<Option<U>> for TraverseControl<U> {
impl<S, U> From<Option<U>> for TraverseControl<S, U> {
fn from(value: Option<U>) -> Self {
match value {
Some(u) => TraverseControl::Return(u),
Expand All @@ -1659,7 +1677,19 @@ pub trait Traverse<T>: Sized {
///
/// Through its return value, `f` can short-circuit one branch of the traversal or
/// the entire traversal.
fn traverse_ref<U>(&self, f: &mut dyn FnMut(&T) -> TraverseControl<U>) -> Option<U>;
///
/// This traversal can make use of "scoped" state. The `scope` argument is passed to
/// each callback, and the callback can optionally override that scope just for its
/// own subtree in the traversal. For example, when traversing a tree of terms you can
/// maintain an environment. Most of the time the environment should get passed around
/// unchanged, but a `Term::Let` should override the environment of its subtree. It
/// does this by returning a `TraverseControl::ContinueWithScope` that contains the
/// new environment.
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&T, &S) -> TraverseControl<S, U>,
scope: &S,
) -> Option<U>;
}

impl Traverse<RichTerm> for RichTerm {
Expand Down Expand Up @@ -1857,16 +1887,22 @@ impl Traverse<RichTerm> for RichTerm {
}
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&RichTerm) -> TraverseControl<U>) -> Option<U> {
match f(self) {
TraverseControl::Continue => {}
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&RichTerm, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
let child_state = match f(self, state) {
TraverseControl::Continue => None,
TraverseControl::ContinueWithScope(s) => Some(s),
TraverseControl::SkipBranch => {
return None;
}
TraverseControl::Return(ret) => {
return Some(ret);
}
};
let state = child_state.as_ref().unwrap_or(state);

match &*self.term {
Term::Null
Expand All @@ -1883,37 +1919,45 @@ impl Traverse<RichTerm> for RichTerm {
| Term::RuntimeError(_) => None,
Term::StrChunks(chunks) => chunks.iter().find_map(|ch| {
if let StrChunk::Expr(term, _) = ch {
term.traverse_ref(f)
term.traverse_ref(f, state)
} else {
None
}
}),
Term::Fun(_, t)
| Term::FunPattern(_, _, t)
| Term::Op1(_, t)
| Term::Sealed(_, t, _) => t.traverse_ref(f),
| Term::Sealed(_, t, _) => t.traverse_ref(f, state),
Term::Let(_, t1, t2, _)
| Term::LetPattern(_, _, t1, t2)
| Term::App(t1, t2)
| Term::Op2(_, t1, t2) => t1.traverse_ref(f).or_else(|| t2.traverse_ref(f)),
Term::Record(data) => data.fields.values().find_map(|field| field.traverse_ref(f)),
| Term::Op2(_, t1, t2) => t1
.traverse_ref(f, state)
.or_else(|| t2.traverse_ref(f, state)),
Term::Record(data) => data
.fields
.values()
.find_map(|field| field.traverse_ref(f, state)),
Term::RecRecord(data, dyn_data, _) => data
.fields
.values()
.find_map(|field| field.traverse_ref(f))
.find_map(|field| field.traverse_ref(f, state))
.or_else(|| {
dyn_data.iter().find_map(|(id, field)| {
id.traverse_ref(f).or_else(|| field.traverse_ref(f))
id.traverse_ref(f, state)
.or_else(|| field.traverse_ref(f, state))
})
}),
Term::Match { cases, default } => cases
.iter()
.find_map(|(_id, t)| t.traverse_ref(f))
.or_else(|| default.as_ref().and_then(|t| t.traverse_ref(f))),
Term::Array(ts, _) => ts.iter().find_map(|t| t.traverse_ref(f)),
Term::OpN(_, ts) => ts.iter().find_map(|t| t.traverse_ref(f)),
Term::Annotated(annot, t) => t.traverse_ref(f).or_else(|| annot.traverse_ref(f)),
Term::Type(ty) => ty.traverse_ref(f),
.find_map(|(_id, t)| t.traverse_ref(f, state))
.or_else(|| default.as_ref().and_then(|t| t.traverse_ref(f, state))),
Term::Array(ts, _) => ts.iter().find_map(|t| t.traverse_ref(f, state)),
Term::OpN(_, ts) => ts.iter().find_map(|t| t.traverse_ref(f, state)),
Term::Annotated(annot, t) => t
.traverse_ref(f, state)
.or_else(|| annot.traverse_ref(f, state)),
Term::Type(ty) => ty.traverse_ref(f, state),
}
}
}
Expand All @@ -1934,11 +1978,18 @@ impl Traverse<Type> for RichTerm {
)
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&Type) -> TraverseControl<U>) -> Option<U> {
self.traverse_ref(&mut |rt: &RichTerm| match &*rt.term {
Term::Type(ty) => ty.traverse_ref(f).into(),
_ => TraverseControl::Continue,
})
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&Type, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
self.traverse_ref(
&mut |rt: &RichTerm, state: &S| match &*rt.term {
Term::Type(ty) => ty.traverse_ref(f, state).into(),
_ => TraverseControl::Continue,
},
state,
)
}
}

Expand Down
12 changes: 8 additions & 4 deletions core/src/term/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,19 @@ impl Traverse<RichTerm> for Field {
})
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&RichTerm) -> TraverseControl<U>) -> Option<U> {
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&RichTerm, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
self.metadata
.annotation
.traverse_ref(f)
.or_else(|| self.value.as_ref().and_then(|v| v.traverse_ref(f)))
.traverse_ref(f, state)
.or_else(|| self.value.as_ref().and_then(|v| v.traverse_ref(f, state)))
.or_else(|| {
self.pending_contracts
.iter()
.find_map(|c| c.traverse_ref(f))
.find_map(|c| c.traverse_ref(f, state))
})
}
}
Expand Down
81 changes: 54 additions & 27 deletions core/src/typ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,11 +624,16 @@ impl Traverse<Type> for RecordRows {
Ok(RecordRows(rows))
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&Type) -> TraverseControl<U>) -> Option<U> {
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&Type, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
match &self.0 {
RecordRowsF::Extend { row, tail } => {
row.typ.traverse_ref(f).or_else(|| tail.traverse_ref(f))
}
RecordRowsF::Extend { row, tail } => row
.typ
.traverse_ref(f, state)
.or_else(|| tail.traverse_ref(f, state)),
_ => None,
}
}
Expand Down Expand Up @@ -1054,10 +1059,13 @@ impl Type {

/// Searches for a `TypeF::Flat`. If one is found, returns the term it contains.
pub fn find_flat(&self) -> Option<RichTerm> {
self.traverse_ref(&mut |ty: &Type| match &ty.typ {
TypeF::Flat(f) => TraverseControl::Return(f.clone()),
_ => TraverseControl::Continue,
})
self.traverse_ref(
&mut |ty: &Type, _: &()| match &ty.typ {
TypeF::Flat(f) => TraverseControl::Return(f.clone()),
_ => TraverseControl::Continue,
},
&(),
)
}
}

Expand Down Expand Up @@ -1089,12 +1097,22 @@ impl Traverse<Type> for Type {
}
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&Type) -> TraverseControl<U>) -> Option<U> {
match f(self) {
TraverseControl::Continue => (),
TraverseControl::SkipBranch => return None,
TraverseControl::Return(ret) => return Some(ret),
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&Type, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
let child_state = match f(self, state) {
TraverseControl::Continue => None,
TraverseControl::ContinueWithScope(s) => Some(s),
TraverseControl::SkipBranch => {
return None;
}
TraverseControl::Return(ret) => {
return Some(ret);
}
};
let state = child_state.as_ref().unwrap_or(state);

match &self.typ {
TypeF::Dyn
Expand All @@ -1105,12 +1123,14 @@ impl Traverse<Type> for Type {
| TypeF::Var(_)
| TypeF::Enum(_)
| TypeF::Wildcard(_) => None,
TypeF::Flat(rt) => rt.traverse_ref(f),
TypeF::Arrow(t1, t2) => t1.traverse_ref(f).or_else(|| t2.traverse_ref(f)),
TypeF::Flat(rt) => rt.traverse_ref(f, state),
TypeF::Arrow(t1, t2) => t1
.traverse_ref(f, state)
.or_else(|| t2.traverse_ref(f, state)),
TypeF::Forall { body: t, .. }
| TypeF::Dict { type_fields: t, .. }
| TypeF::Array(t) => t.traverse_ref(f),
TypeF::Record(rrows) => rrows.traverse_ref(f),
| TypeF::Array(t) => t.traverse_ref(f, state),
TypeF::Record(rrows) => rrows.traverse_ref(f, state),
}
}
}
Expand All @@ -1131,17 +1151,24 @@ impl Traverse<RichTerm> for Type {
)
}

fn traverse_ref<U>(&self, f: &mut dyn FnMut(&RichTerm) -> TraverseControl<U>) -> Option<U> {
self.traverse_ref(&mut |ty: &Type| match &ty.typ {
TypeF::Flat(t) => {
if let Some(ret) = t.traverse_ref(f) {
TraverseControl::Return(ret)
} else {
TraverseControl::SkipBranch
fn traverse_ref<S, U>(
&self,
f: &mut dyn FnMut(&RichTerm, &S) -> TraverseControl<S, U>,
state: &S,
) -> Option<U> {
self.traverse_ref(
&mut |ty: &Type, s: &S| match &ty.typ {
TypeF::Flat(t) => {
if let Some(ret) = t.traverse_ref(f, s) {
TraverseControl::Return(ret)
} else {
TraverseControl::SkipBranch
}
}
}
_ => TraverseControl::Continue,
})
_ => TraverseControl::Continue,
},
state,
)
}
}

Expand Down
2 changes: 1 addition & 1 deletion lsp/nls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ name = "nls"
path = "src/main.rs"

[features]
default = ["format", "old-completer"]
default = ["format"]
format = ["nickel-lang-core/format"]
old-completer = []

Expand Down
13 changes: 13 additions & 0 deletions lsp/nls/src/field_walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ pub struct DefWithPath {
pub metadata: Option<FieldMetadata>,
}

impl DefWithPath {
pub fn completion_item(&self) -> CompletionItem {
CompletionItem {
label: ident_quoted(&self.ident.into()),
detail: self.metadata.as_ref().and_then(metadata_detail),
kind: Some(CompletionItemKind::Property),
documentation: self.metadata.as_ref().and_then(metadata_doc),
..Default::default()
}
}
}

#[cfg(test)]
impl DefWithPath {
pub fn path(&self) -> &[Ident] {
Expand Down Expand Up @@ -242,6 +254,7 @@ impl<'a> FieldResolver<'a> {
let defs = self.resolve_annot(annot);
defs.chain(self.resolve_term(term)).collect()
}
Term::Type(typ) => self.resolve_type(typ),
_ => Default::default(),
};

Expand Down
4 changes: 4 additions & 0 deletions lsp/nls/src/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ pub fn handle_save(server: &mut Server, params: DidChangeTextDocumentParams) ->
let invalid = server.cache.get_rev_imports_transitive(file_id);
for f in &invalid {
server.lin_registry.map.remove(f);
server.lin_registry.position_lookups.remove(f);
server.lin_registry.usage_lookups.remove(f);
server.lin_registry.parent_lookups.remove(f);
server.lin_registry.type_lookups.remove(f);
}

// TODO: make this part more abstracted
Expand Down
Loading