Skip to content
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
84 changes: 46 additions & 38 deletions crates/squawk_ide/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,36 @@
/// see: typescript-go/internal/binder/binder.go
use la_arena::Arena;
use rowan::TextSize;
use smallvec::SmallVec;
use squawk_syntax::{SyntaxNodePtr, ast, ast::AstNode};

use crate::scope::Scope;
use crate::symbols::{Name, Schema, Symbol, SymbolKind};

type Schemas = SmallVec<[Schema; 3]>;

pub(crate) struct ResolvedSchemas {
list: Schemas,
unqualified: bool,
}

impl ResolvedSchemas {
pub(crate) fn list(&self) -> &[Schema] {
&self.list
}

pub(crate) fn unqualified(&self) -> bool {
self.unqualified
}

pub(crate) fn from_single(schema: Schema) -> Self {
Self {
list: Schemas::from_iter([schema]),
unqualified: false,
}
}
}

#[derive(Clone, PartialEq)]
struct SearchPathChange {
position: TextSize,
Expand Down Expand Up @@ -45,23 +70,27 @@ impl Binder {
Some(self.symbols[symbol_id].ptr)
}

pub(crate) fn resolved_schemas(
&self,
position: TextSize,
schema: Option<&Schema>,
) -> ResolvedSchemas {
let unqualified = schema.is_none();
let list = match schema {
Some(s) => Schemas::from_iter([s.clone()]),
None => self.search_path_at(position).iter().cloned().collect(),
};
ResolvedSchemas { list, unqualified }
}

pub(crate) fn lookup_with(
&self,
name: &Name,
kind: SymbolKind,
position: TextSize,
schema: Option<&Schema>,
schemas: &ResolvedSchemas,
) -> Option<SyntaxNodePtr> {
let symbols = self.scope.get(name)?;

// TODO: we should just require Schema, rather than doing the lookup in
// here. Having to thread position is annoying.
let search_paths = match schema {
Some(s) => std::slice::from_ref(s),
None => self.search_path_at(position),
};

for search_schema in search_paths {
for search_schema in schemas.list() {
if let Some(symbol_id) = symbols.iter().copied().find(|id| {
let symbol = &self.symbols[*id];
symbol.kind == kind && symbol.schema.as_ref() == Some(search_schema)
Expand All @@ -76,18 +105,11 @@ impl Binder {
&self,
name: &Name,
kind: SymbolKind,
position: TextSize,
schema: Option<&Schema>,
schemas: &ResolvedSchemas,
params: Option<&[Name]>,
) -> Option<SyntaxNodePtr> {
let symbols = self.scope.get(name)?;

let search_paths = match schema {
Some(s) => std::slice::from_ref(s),
None => self.search_path_at(position),
};

for search_schema in search_paths {
for search_schema in schemas.list() {
if let Some(symbol_id) = symbols.iter().copied().find(|id| {
let symbol = &self.symbols[*id];
let params_match = match (&symbol.params, params) {
Expand All @@ -108,18 +130,11 @@ impl Binder {
&self,
name: &Name,
kind: SymbolKind,
position: TextSize,
schema: Option<&Schema>,
schemas: &ResolvedSchemas,
table: &Option<Name>,
) -> Option<SyntaxNodePtr> {
let symbols = self.scope.get(name)?;

let search_paths = match schema {
Some(s) => std::slice::from_ref(s),
None => self.search_path_at(position),
};

for search_schema in search_paths {
for search_schema in schemas.list() {
if let Some(symbol_id) = symbols.iter().copied().find(|id| {
let symbol = &self.symbols[*id];
symbol.kind == kind
Expand All @@ -135,18 +150,11 @@ impl Binder {
pub(crate) fn lookup_info(
&self,
name: &Name,
schema: Option<&Schema>,
kind: SymbolKind,
position: TextSize,
schemas: &ResolvedSchemas,
) -> Option<(Schema, String)> {
let symbols = self.scope.get(name)?;

let search_paths: &[Schema] = match schema {
Some(s) => std::slice::from_ref(s),
None => self.search_path_at(position),
};

for search_schema in search_paths {
for search_schema in schemas.list() {
if let Some(symbol_id) = symbols.iter().copied().find(|id| {
let symbol = &self.symbols[*id];
symbol.kind == kind && symbol.schema.as_ref() == Some(search_schema)
Expand Down
85 changes: 28 additions & 57 deletions crates/squawk_ide/src/collect.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::ast_nav;
use crate::column_name::ColumnName;
use crate::db::{File, list_files, parse};
use crate::db::{File, bind, list_files, parse};
use crate::file::InFile;
use crate::goto_definition::goto_definition;
use crate::infer::{Type, infer_type_from_expr, infer_type_from_ty};
Expand Down Expand Up @@ -43,12 +43,8 @@ fn columns_from_create_table_impl(
ast_nav::CreateTableArg::Inherits(path) => {
if let Some((schema, table_name)) = name::schema_and_name_path(&path) {
let position = path.syntax().text_range().start();
if let Some(resolved) = resolve_table_name(
db,
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
if let Some(resolved) = resolve_table_name(db, &table_name, &schemas, file) {
columns.extend(resolved_to_column_ptrs(
db,
resolved.file_id,
Expand All @@ -72,12 +68,8 @@ fn columns_from_create_table_impl(
&& let Some((schema, table_name)) = name::schema_and_name_path(&path)
{
let position = path.syntax().text_range().start();
if let Some(resolved) = resolve_table_name(
db,
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
if let Some(resolved) = resolve_table_name(db, &table_name, &schemas, file) {
columns.extend(resolved_to_column_ptrs(
db,
resolved.file_id,
Expand Down Expand Up @@ -154,12 +146,8 @@ fn table_columns_impl(
ast_nav::CreateTableArg::Inherits(path) => {
if let Some((schema, table_name)) = name::schema_and_name_path(&path) {
let position = path.syntax().text_range().start();
if let Some(resolved) = resolve_table_name(
db,
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
if let Some(resolved) = resolve_table_name(db, &table_name, &schemas, file) {
columns.extend(resolved_to_columns_with_types(
db,
resolved.file_id,
Expand All @@ -180,12 +168,8 @@ fn table_columns_impl(
&& let Some((schema, table_name)) = name::schema_and_name_path(&path)
{
let position = path.syntax().text_range().start();
if let Some(resolved) = resolve_table_name(
db,
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
if let Some(resolved) = resolve_table_name(db, &table_name, &schemas, file) {
columns.extend(resolved_to_columns_with_types(
db,
resolved.file_id,
Expand Down Expand Up @@ -305,14 +289,11 @@ fn select_columns_with_types(
};
let name_ref = path.segment().and_then(|s| s.name_ref());
let position = table.syntax().text_range().start();
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
// Try CTE resolution first since resolve_table_name doesn't handle CTEs
if let Some((ptr, kind)) = resolve_table_like(
db,
name_ref.as_ref(),
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
if let Some((ptr, kind)) =
resolve_table_like(db, name_ref.as_ref(), &table_name, &schemas, file)
{
let tree = parse(db, file).tree();
let node = ptr.to_node(tree.syntax());
match kind {
Expand All @@ -333,12 +314,7 @@ fn select_columns_with_types(
}
}
// Fall back to builtins for schema-qualified names
if let Some(resolved) = resolve_table_name(
db,
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
if let Some(resolved) = resolve_table_name(db, &table_name, &schemas, file) {
return resolved_to_columns_with_types(db, resolved.file_id, resolved.value, 0);
}
vec![]
Expand Down Expand Up @@ -414,19 +390,17 @@ fn returning_target_list_columns_with_types(

if target.star_token().is_some()
&& let Some((schema, table_name)) = name::schema_and_name_path(path)
&& let Some(resolved) = resolve_table_name(
db,
&table_name,
schema.as_ref(),
InFile::new(file, target.syntax().text_range().start()),
)
{
columns.extend(resolved_to_columns_with_types(
db,
resolved.file_id,
resolved.value,
0,
));
let position = target.syntax().text_range().start();
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
if let Some(resolved) = resolve_table_name(db, &table_name, &schemas, file) {
columns.extend(resolved_to_columns_with_types(
db,
resolved.file_id,
resolved.value,
0,
));
}
}
}
}
Expand Down Expand Up @@ -802,13 +776,10 @@ fn select_variant_columns_with_types(
};
let name_ref = path.segment().and_then(|segment| segment.name_ref());
let position = table.syntax().text_range().start();
let Some((ptr, kind)) = resolve_table_like(
db,
name_ref.as_ref(),
&table_name,
schema.as_ref(),
InFile::new(file, position),
) else {
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
let Some((ptr, kind)) =
resolve_table_like(db, name_ref.as_ref(), &table_name, &schemas, file)
else {
return vec![];
};
let node = ptr.to_node(root);
Expand Down
18 changes: 8 additions & 10 deletions crates/squawk_ide/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,15 +674,12 @@ fn delete_expr_completions(
}

let schema = name::schema_name(&path);
if let Some(table_ptr) = binder.lookup_with(
&delete_table_name,
SymbolKind::Table,
position,
schema.as_ref(),
) && let Some(create_table) = table_ptr
.to_node(source_file.syntax())
.ancestors()
.find_map(ast::CreateTableLike::cast)
let schemas = binder.resolved_schemas(position, schema.as_ref());
if let Some(table_ptr) = binder.lookup_with(&delete_table_name, SymbolKind::Table, &schemas)
&& let Some(create_table) = table_ptr
.to_node(source_file.syntax())
.ancestors()
.find_map(ast::CreateTableLike::cast)
{
let columns = collect::table_columns(db, file, &create_table);
completions.extend(columns.into_iter().map(|(name, ty)| CompletionItem {
Expand Down Expand Up @@ -849,8 +846,9 @@ fn function_detail(
) -> Option<String> {
let binder = bind(db, file);
let source_file = parse(db, file).tree();
let schemas = binder.resolved_schemas(position, schema);
let create_function = binder
.lookup_with(function_name, SymbolKind::Function, position, schema)?
.lookup_with(function_name, SymbolKind::Function, &schemas)?
.to_node(source_file.syntax())
.ancestors()
.find_map(ast::CreateFunction::cast)?;
Expand Down
22 changes: 8 additions & 14 deletions crates/squawk_ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1520,13 +1520,10 @@ fn qualified_star_table_ptr(
let (schema, table_name) = name::schema_and_table_from_from_item(&from_item)?;

let name_ref = from_item.name_ref();
if let Some((table_like_ptr, _kind)) = resolve::resolve_table_like(
db,
name_ref.as_ref(),
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());
if let Some((table_like_ptr, _kind)) =
resolve::resolve_table_like(db, name_ref.as_ref(), &table_name, &schemas, file)
{
return Some(table_like_ptr);
}

Expand All @@ -1553,14 +1550,11 @@ fn table_or_view_or_cte_ptrs(
let (schema, table_name) = name::schema_and_name_path(path)?;
let mut results = vec![];
let name_ref = path.segment().and_then(|x| x.name_ref());
let schemas = bind(db, file).resolved_schemas(position, schema.as_ref());

if let Some((table_like_ptr, _kind)) = resolve::resolve_table_like(
db,
name_ref.as_ref(),
&table_name,
schema.as_ref(),
InFile::new(file, position),
) {
if let Some((table_like_ptr, _kind)) =
resolve::resolve_table_like(db, name_ref.as_ref(), &table_name, &schemas, file)
{
results.push(table_like_ptr);
}

Expand Down
Loading
Loading