mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge branch 'main' into inline-imports
This commit is contained in:
commit
4476277a56
28 changed files with 142 additions and 84 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2665,7 +2665,7 @@ name = "roc_ident"
|
|||
version = "0.0.1"
|
||||
|
||||
[[package]]
|
||||
name = "roc_lang_srv"
|
||||
name = "roc_language_server"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
|
|
|
@ -27,7 +27,7 @@ members = [
|
|||
"crates/wasi-libc-sys",
|
||||
"crates/wasm_module",
|
||||
"crates/wasm_interp",
|
||||
"crates/lang_srv",
|
||||
"crates/language_server",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
@ -195,4 +195,4 @@ lto = "thin" # TODO: We could consider full here since this is only used for pac
|
|||
|
||||
[profile.debug-full]
|
||||
inherits = "dev"
|
||||
debug = true
|
||||
debug = true
|
||||
|
|
|
@ -33,6 +33,8 @@ If you would like your company to become a corporate sponsor of Roc's developmen
|
|||
|
||||
We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more:
|
||||
|
||||
* [Angelo Ceccato](https://github.com/AngeloChecked)
|
||||
* [Niclas Overby](https://github.com/noverby)
|
||||
* [Krzysztof G.](https://github.com/krzysztofgb)
|
||||
* [Sam Mohr](https://github.com/smores56)
|
||||
* [Steven Chen](https://github.com/megakilo)
|
||||
|
|
|
@ -197,17 +197,12 @@ where
|
|||
)
|
||||
}
|
||||
|
||||
pub fn check_indent<'a, E>(
|
||||
indent_problem: fn(Position) -> E,
|
||||
inside_suffixed_statement: bool,
|
||||
) -> impl Parser<'a, (), E>
|
||||
pub fn check_indent<'a, E>(indent_problem: fn(Position) -> E) -> impl Parser<'a, (), E>
|
||||
where
|
||||
E: 'a,
|
||||
{
|
||||
let extra_spaces = if inside_suffixed_statement { 1 } else { 0 };
|
||||
|
||||
move |_, state: State<'a>, min_indent: u32| {
|
||||
if state.column() >= (min_indent + extra_spaces) {
|
||||
if state.column() >= min_indent {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
Err((NoProgress, indent_problem(state.pos())))
|
||||
|
|
|
@ -1772,11 +1772,13 @@ fn finish_parsing_ability_def_help<'a>(
|
|||
Ok((MadeProgress, (type_def, def_region), state))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn parse_expr_operator<'a>(
|
||||
min_indent: u32,
|
||||
options: ExprParseOptions,
|
||||
mut expr_state: ExprState<'a>,
|
||||
loc_op: Loc<BinOp>,
|
||||
line_indent: u32,
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
initial_state: State<'a>,
|
||||
|
@ -1821,7 +1823,8 @@ fn parse_expr_operator<'a>(
|
|||
}
|
||||
BinOp::Assignment => {
|
||||
let expr_region = expr_state.expr.region;
|
||||
let indented_more = min_indent + 1;
|
||||
|
||||
let indented_more = line_indent + 1;
|
||||
|
||||
let call = expr_state
|
||||
.validate_assignment_or_backpassing(arena, loc_op, EExpr::ElmStyleFunction)
|
||||
|
@ -2028,12 +2031,18 @@ fn parse_expr_end<'a>(
|
|||
state: State<'a>,
|
||||
initial_state: State<'a>,
|
||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||
let inner_min_indent = if options.suffixed_found {
|
||||
min_indent + 1
|
||||
} else {
|
||||
min_indent
|
||||
};
|
||||
|
||||
let parser = skip_first!(
|
||||
crate::blankspace::check_indent(EExpr::IndentEnd, options.suffixed_found),
|
||||
crate::blankspace::check_indent(EExpr::IndentEnd),
|
||||
loc_term_or_underscore(options)
|
||||
);
|
||||
|
||||
match parser.parse(arena, state.clone(), min_indent) {
|
||||
match parser.parse(arena, state.clone(), inner_min_indent) {
|
||||
Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
Ok((
|
||||
_,
|
||||
|
@ -2135,6 +2144,7 @@ fn parse_expr_end<'a>(
|
|||
Err((NoProgress, _)) => {
|
||||
let before_op = state.clone();
|
||||
// try an operator
|
||||
let line_indent = state.line_indent();
|
||||
match loc!(operator()).parse(arena, state.clone(), min_indent) {
|
||||
Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
Ok((_, loc_op, state)) => {
|
||||
|
@ -2145,6 +2155,7 @@ fn parse_expr_end<'a>(
|
|||
options,
|
||||
expr_state,
|
||||
loc_op,
|
||||
line_indent,
|
||||
arena,
|
||||
state,
|
||||
initial_state,
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn closure_param<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
|||
|
||||
pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
move |arena, state: State<'a>, min_indent| {
|
||||
let (_, pattern, state) = loc_pattern_help_help().parse(arena, state, min_indent)?;
|
||||
let (_, pattern, state) = loc_pattern_help_help(true).parse(arena, state, min_indent)?;
|
||||
|
||||
let pattern_state = state.clone();
|
||||
|
||||
|
@ -82,11 +82,13 @@ pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>>
|
|||
}
|
||||
}
|
||||
|
||||
fn loc_pattern_help_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
fn loc_pattern_help_help<'a>(
|
||||
can_have_arguments: bool,
|
||||
) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
one_of!(
|
||||
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||
loc!(underscore_pattern_help()),
|
||||
loc_ident_pattern_help(true),
|
||||
loc_ident_pattern_help(can_have_arguments),
|
||||
loc!(specialize_err(
|
||||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help()
|
||||
|
@ -143,7 +145,8 @@ fn loc_tag_pattern_arg<'a>(
|
|||
min_indent,
|
||||
)?;
|
||||
|
||||
let (_, loc_pat, state) = loc_parse_tag_pattern_arg().parse(arena, state, min_indent)?;
|
||||
// Cannot have arguments here, pass `false` to make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
||||
let (_, loc_pat, state) = loc_pattern_help_help(false).parse(arena, state, min_indent)?;
|
||||
|
||||
let Loc { region, value } = loc_pat;
|
||||
|
||||
|
@ -194,21 +197,6 @@ pub fn loc_implements_parser<'a>() -> impl Parser<'a, Loc<Implements<'a>>, EPatt
|
|||
)
|
||||
}
|
||||
|
||||
fn loc_parse_tag_pattern_arg<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
one_of!(
|
||||
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||
loc!(underscore_pattern_help()),
|
||||
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
||||
loc_ident_pattern_help(false),
|
||||
loc!(specialize_err(
|
||||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help()
|
||||
)),
|
||||
loc!(string_like_pattern_help()),
|
||||
loc!(number_pattern_help())
|
||||
)
|
||||
}
|
||||
|
||||
fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInParens<'a>> {
|
||||
then(
|
||||
loc!(collection_trailing_sep_e!(
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
name = "test_syntax-fuzz"
|
||||
publish = false
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
version = "0.0.0"
|
||||
authors = ["Automatically generated"]
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
@ -12,8 +12,8 @@ cargo-fuzz = true
|
|||
[dependencies]
|
||||
test_syntax = { path = "../../test_syntax" }
|
||||
|
||||
bumpalo.workspace = true
|
||||
libfuzzer-sys.workspace = true
|
||||
bumpalo = { version = "3.12.0", features = ["collections"] }
|
||||
libfuzzer-sys = "0.4"
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
When(
|
||||
@5-10 Apply(
|
||||
@5-7 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@8-10 List(
|
||||
[],
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@18-23 SpaceBefore(
|
||||
Apply(
|
||||
@18-20 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@21-23 List(
|
||||
[],
|
||||
),
|
||||
],
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @27-29 Record(
|
||||
[],
|
||||
),
|
||||
guard: None,
|
||||
},
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@34-35 SpaceBefore(
|
||||
Underscore(
|
||||
"",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @39-41 Record(
|
||||
[],
|
||||
),
|
||||
guard: None,
|
||||
},
|
||||
],
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
when Ok [] is
|
||||
Ok [] -> {}
|
||||
_ -> {}
|
|
@ -491,6 +491,7 @@ mod test_snapshots {
|
|||
pass/when_in_function_python_style_indent.expr,
|
||||
pass/when_in_parens.expr,
|
||||
pass/when_in_parens_indented.expr,
|
||||
pass/when_result_list.expr,
|
||||
pass/when_with_alternative_patterns.expr,
|
||||
pass/when_with_function_application.expr,
|
||||
pass/when_with_negative_numbers.expr,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "roc_lang_srv"
|
||||
name = "roc_language_server"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
|
@ -33,50 +33,49 @@ use self::{analysed_doc::ModuleIdToUrl, tokens::Token};
|
|||
|
||||
pub const HIGHLIGHT_TOKENS_LEGEND: &[SemanticTokenType] = Token::LEGEND;
|
||||
|
||||
/// Contains hashmaps of info about all modules that were analyzed
|
||||
#[derive(Debug)]
|
||||
pub(super) struct ModulesInfo {
|
||||
subs: Mutex<HashMap<ModuleId, Subs>>,
|
||||
exposed: HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
||||
docs: VecMap<ModuleId, ModuleDocumentation>,
|
||||
struct ModulesInfo {
|
||||
subs_by_module: HashMap<ModuleId, Mutex<Subs>>,
|
||||
exposed_by_module: HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
||||
docs_by_module: HashMap<ModuleId, ModuleDocumentation>,
|
||||
}
|
||||
|
||||
impl ModulesInfo {
|
||||
fn with_subs<F, A>(&self, mod_id: &ModuleId, f: F) -> Option<A>
|
||||
fn with_subs<F, A>(&self, module_id: &ModuleId, f: F) -> Option<A>
|
||||
where
|
||||
F: FnOnce(&mut Subs) -> A,
|
||||
{
|
||||
self.subs.lock().get_mut(mod_id).map(f)
|
||||
let subs = self.subs_by_module.get(module_id)?;
|
||||
Some(f(&mut subs.lock()))
|
||||
}
|
||||
/// Transforms some of the raw data from the analysis into a state that is
|
||||
/// more useful during processes like completion.
|
||||
fn from_analysis(
|
||||
|
||||
fn get_docs(&self, module_id: &ModuleId) -> Option<&ModuleDocumentation> {
|
||||
self.docs_by_module.get(module_id)
|
||||
}
|
||||
|
||||
fn from_loaded_module(
|
||||
exposes: MutMap<ModuleId, Vec<(Symbol, Variable)>>,
|
||||
typechecked: &MutMap<ModuleId, CheckedModule>,
|
||||
docs_by_module: VecMap<ModuleId, ModuleDocumentation>,
|
||||
) -> ModulesInfo {
|
||||
// We wrap this in Arc because later we will go through each module's imports and
|
||||
// store the full list of symbols that each imported module exposes.
|
||||
// example: A imports B. B exposes [add, multiply, divide] and A will store a reference to that list.
|
||||
let exposed = exposes
|
||||
let exposed_by_module = exposes
|
||||
.into_iter()
|
||||
.map(|(module_id, symbols)| (module_id, Arc::new(symbols)))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// Combine the subs from all modules
|
||||
let all_subs = Mutex::new(
|
||||
typechecked
|
||||
.iter()
|
||||
.map(|(module_id, checked_module)| {
|
||||
(*module_id, checked_module.solved_subs.0.clone())
|
||||
})
|
||||
.collect::<HashMap<_, _>>(),
|
||||
);
|
||||
let subs_by_module = typechecked
|
||||
.iter()
|
||||
.map(|(module_id, checked_module)| {
|
||||
(*module_id, checked_module.solved_subs.0.clone().into())
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let docs_by_module = docs_by_module.into_iter().collect();
|
||||
|
||||
ModulesInfo {
|
||||
subs: all_subs,
|
||||
exposed,
|
||||
docs: docs_by_module,
|
||||
subs_by_module,
|
||||
exposed_by_module,
|
||||
docs_by_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,15 +83,14 @@ impl ModulesInfo {
|
|||
#[derive(Debug, Clone)]
|
||||
pub(super) struct AnalyzedModule {
|
||||
exposed_imports: Vec<(Symbol, Variable)>,
|
||||
/// imports are grouped by which module they come from
|
||||
imports: HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
||||
imports_by_module: HashMap<ModuleId, Arc<Vec<(Symbol, Variable)>>>,
|
||||
module_id: ModuleId,
|
||||
interns: Interns,
|
||||
subs: Subs,
|
||||
abilities: AbilitiesStore,
|
||||
declarations: Declarations,
|
||||
modules_info: Arc<ModulesInfo>,
|
||||
// We need this because ModuleIds are not stable between compilations, so a ModuleId visible to
|
||||
// ModuleIds are not stable between compilations, so a ModuleId visible to
|
||||
// one module may not be true global to the language server.
|
||||
module_id_to_url: ModuleIdToUrl,
|
||||
}
|
||||
|
@ -164,7 +162,7 @@ pub(crate) fn global_analysis(doc_info: DocInfo) -> Vec<AnalyzedDocument> {
|
|||
|
||||
let exposed_imports = resolve_exposed_imports(exposed_imports, &exposes);
|
||||
|
||||
let modules_info = Arc::new(ModulesInfo::from_analysis(
|
||||
let modules_info = Arc::new(ModulesInfo::from_loaded_module(
|
||||
exposes,
|
||||
&typechecked,
|
||||
docs_by_module,
|
||||
|
@ -304,7 +302,7 @@ impl<'a> AnalyzedDocumentBuilder<'a> {
|
|||
|
||||
let analyzed_module = AnalyzedModule {
|
||||
exposed_imports,
|
||||
imports,
|
||||
imports_by_module: imports,
|
||||
subs,
|
||||
abilities,
|
||||
declarations,
|
||||
|
@ -342,7 +340,7 @@ impl<'a> AnalyzedDocumentBuilder<'a> {
|
|||
(
|
||||
id,
|
||||
self.modules_info
|
||||
.exposed
|
||||
.exposed_by_module
|
||||
.get(&id)
|
||||
.unwrap_or(&Arc::new(vec![]))
|
||||
.clone(),
|
|
@ -69,6 +69,7 @@ impl DocInfo {
|
|||
let end = Position::new(self.line_info.num_lines(), 0);
|
||||
Range::new(start, end)
|
||||
}
|
||||
|
||||
pub fn get_prefix_at_position(&self, position: Position) -> String {
|
||||
let position = position.to_roc_position(&self.line_info);
|
||||
let offset = position.offset as usize;
|
||||
|
@ -82,6 +83,7 @@ impl DocInfo {
|
|||
|
||||
String::from(symbol)
|
||||
}
|
||||
|
||||
pub fn format(&self) -> Option<Vec<TextEdit>> {
|
||||
let source = &self.source;
|
||||
let arena = &Bump::new();
|
||||
|
@ -175,10 +177,12 @@ impl AnalyzedDocument {
|
|||
|
||||
let (region, var) = roc_can::traverse::find_closest_type_at(pos, declarations)?;
|
||||
|
||||
//TODO:Can this be integrated into find closest type? is it even worth it?
|
||||
let docs_opt = self
|
||||
.symbol_at(position)
|
||||
.and_then(|symb| modules_info.docs.get(module_id)?.get_doc_for_symbol(&symb));
|
||||
//TODO: Can this be integrated into "find closest type"? Is it worth it?
|
||||
let docs_opt = self.symbol_at(position).and_then(|symbol| {
|
||||
modules_info
|
||||
.get_docs(module_id)?
|
||||
.get_doc_for_symbol(&symbol)
|
||||
});
|
||||
|
||||
let type_str = format_var_type(var, &mut subs.clone(), module_id, interns);
|
||||
|
||||
|
@ -238,7 +242,7 @@ impl AnalyzedDocument {
|
|||
subs,
|
||||
declarations,
|
||||
exposed_imports,
|
||||
imports,
|
||||
imports_by_module: imports,
|
||||
modules_info,
|
||||
..
|
||||
} = self.module()?;
|
||||
|
@ -299,7 +303,7 @@ impl AnalyzedDocument {
|
|||
&mut subs.clone(),
|
||||
module_id,
|
||||
interns,
|
||||
modules_info.docs.get(module_id),
|
||||
modules_info.get_docs(module_id),
|
||||
exposed_imports,
|
||||
);
|
||||
Some(completions)
|
|
@ -77,7 +77,7 @@ pub(super) fn get_module_completion_items(
|
|||
mod_id,
|
||||
interns,
|
||||
exposed_symbols,
|
||||
modules_info.docs.get(mod_id),
|
||||
modules_info.get_docs(mod_id),
|
||||
modules_info,
|
||||
)),
|
||||
..Default::default()
|
||||
|
@ -90,7 +90,7 @@ pub(super) fn get_module_completion_items(
|
|||
exposed_symbols,
|
||||
modules_info,
|
||||
mod_id,
|
||||
modules_info.docs.get(mod_id),
|
||||
modules_info.get_docs(mod_id),
|
||||
interns,
|
||||
)
|
||||
} else {
|
|
@ -146,12 +146,14 @@ If you would like your organization to become an official sponsor of Roc's devel
|
|||
We'd also like to express our gratitude to our generous [individual sponsors](https://github.com/sponsors/roc-lang/)! A special thanks to those sponsoring $25/month or more:
|
||||
|
||||
<ul id="individual-sponsors">
|
||||
<li><a href="https://github.com/krzysztofgb">Krzysztof G.</a>
|
||||
<li><a href="https://github.com/smores56">Sam Mohr</a>
|
||||
<li><a href="https://github.com/megakilo">Steven Chen</a>
|
||||
<li><a href="https://github.com/asteroidb612">Drew Lazzeri</a>
|
||||
<li><a href="https://github.com/mrmizz">Alex Binaei</a>
|
||||
<li><a href="https://github.com/jonomallanyk">Jono Mallanyk</a>
|
||||
<li><a href="https://github.com/AngeloChecked">Angelo Ceccato</a></li>
|
||||
<li><a href="https://github.com/noverby">Niclas Overby</a></li>
|
||||
<li><a href="https://github.com/krzysztofgb">Krzysztof G.</a></li>
|
||||
<li><a href="https://github.com/smores56">Sam Mohr</a></li>
|
||||
<li><a href="https://github.com/megakilo">Steven Chen</a></li>
|
||||
<li><a href="https://github.com/asteroidb612">Drew Lazzeri</a></li>
|
||||
<li><a href="https://github.com/mrmizz">Alex Binaei</a></li>
|
||||
<li><a href="https://github.com/jonomallanyk">Jono Mallanyk</a></li>
|
||||
<li><a href="https://github.com/chris-packett">Chris Packett</a></li>
|
||||
<li><a href="https://github.com/jamesbirtles">James Birtles</a></li>
|
||||
<li><a href="https://github.com/Ivo-Balbaert">Ivo Balbaert</a></li>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue