mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-11 18:58:24 +03:00
Load and can new top-level imports
Previously, all imports were available in the header, so we could start processing dependencies as soon as we parsed it. However, the new imports are treated as defs, so we have to parse the whole module to find them. This commit essentially moves the dependency resolution from the `LoadHeader` phase to the `Parse` phase, and it updates canonicalization to introduce module symbols into scope when a `ValueDef::ModuleImport` is encountered. NOTE: - The `imports` header still parses, but it's no longer wired up. I will remove it in an upcoming commit. - Ingested files and imports that appear in nested expressions are not yet supported by load
This commit is contained in:
parent
11e0202eb9
commit
710d62f754
@ -30,27 +30,27 @@ interface Decode
|
||||
fromBytes,
|
||||
mapResult,
|
||||
]
|
||||
imports [
|
||||
List,
|
||||
Result.{ Result },
|
||||
Num.{
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
Nat,
|
||||
F32,
|
||||
F64,
|
||||
Dec,
|
||||
},
|
||||
Bool.{ Bool },
|
||||
]
|
||||
imports []
|
||||
|
||||
import List
|
||||
import Result exposing [Result]
|
||||
import Num exposing [
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
Nat,
|
||||
F32,
|
||||
F64,
|
||||
Dec,
|
||||
]
|
||||
import Bool exposing [Bool]
|
||||
|
||||
## Error types when decoding a `List U8` of utf-8 bytes using a [Decoder]
|
||||
DecodeError : [TooShort]
|
||||
|
@ -29,15 +29,15 @@ interface Dict
|
||||
map,
|
||||
joinMap,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool, Eq },
|
||||
Result.{ Result },
|
||||
List,
|
||||
Str,
|
||||
Num.{ Nat, U64, F32, U32, U8, I8 },
|
||||
Hash.{ Hasher, Hash },
|
||||
Inspect.{ Inspect, Inspector, InspectFormatter },
|
||||
]
|
||||
imports []
|
||||
|
||||
import Bool exposing [Bool, Eq]
|
||||
import Result exposing [Result]
|
||||
import List
|
||||
import Str
|
||||
import Num exposing [Nat, U64, F32, U32, U8, I8]
|
||||
import Hash exposing [Hasher, Hash]
|
||||
import Inspect exposing [Inspect, Inspector, InspectFormatter]
|
||||
|
||||
## A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you
|
||||
## associate keys with values.
|
||||
|
@ -28,24 +28,24 @@ interface Encode
|
||||
append,
|
||||
toBytes,
|
||||
]
|
||||
imports [
|
||||
Num.{
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
F32,
|
||||
F64,
|
||||
Dec,
|
||||
},
|
||||
Bool.{ Bool },
|
||||
]
|
||||
imports []
|
||||
|
||||
import Num exposing [
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
F32,
|
||||
F64,
|
||||
Dec,
|
||||
]
|
||||
import Bool exposing [Bool]
|
||||
|
||||
Encoder fmt := List U8, fmt -> List U8 where fmt implements EncoderFormatting
|
||||
|
||||
|
@ -21,12 +21,25 @@ interface Hash
|
||||
hashStrBytes,
|
||||
hashList,
|
||||
hashUnordered,
|
||||
] imports [
|
||||
Bool.{ Bool, isEq },
|
||||
List,
|
||||
Str,
|
||||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, Nat, Dec },
|
||||
]
|
||||
] imports []
|
||||
|
||||
import Bool exposing [Bool, isEq]
|
||||
import List
|
||||
import Str
|
||||
import Num exposing [
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
Nat,
|
||||
Dec,
|
||||
]
|
||||
|
||||
## A value that can be hashed.
|
||||
Hash implements
|
||||
|
@ -36,12 +36,12 @@ interface Inspect
|
||||
toInspector,
|
||||
toStr,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec, Nat },
|
||||
List,
|
||||
Str,
|
||||
]
|
||||
imports []
|
||||
|
||||
import Bool exposing [Bool]
|
||||
import Num exposing [U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec, Nat]
|
||||
import List
|
||||
import Str
|
||||
|
||||
KeyValWalker state collection key val : collection, state, (state, key, val -> state) -> state
|
||||
ElemWalker state collection elem : collection, state, (state, elem -> state) -> state
|
||||
|
@ -71,11 +71,11 @@ interface List
|
||||
countIf,
|
||||
chunksOf,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool, Eq },
|
||||
Result.{ Result },
|
||||
Num.{ Nat, Num, Int },
|
||||
]
|
||||
imports []
|
||||
|
||||
import Bool exposing [Bool, Eq]
|
||||
import Result exposing [Result]
|
||||
import Num exposing [Nat, Num, Int]
|
||||
|
||||
## ## Types
|
||||
##
|
||||
|
@ -158,10 +158,10 @@ interface Num
|
||||
toF64,
|
||||
toF64Checked,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
Result.{ Result },
|
||||
]
|
||||
imports []
|
||||
|
||||
import Bool exposing [Bool]
|
||||
import Result exposing [Result]
|
||||
|
||||
## Represents a number that could be either an [Int] or a [Frac].
|
||||
##
|
||||
|
@ -1,6 +1,8 @@
|
||||
interface Result
|
||||
exposes [Result, isOk, isErr, map, mapErr, try, onErr, withDefault]
|
||||
imports [Bool.{ Bool }]
|
||||
imports []
|
||||
|
||||
import Bool exposing [Bool]
|
||||
|
||||
## The result of an operation that could fail: either the operation went
|
||||
## okay, or else there was an error of some sort.
|
||||
|
@ -24,14 +24,14 @@ interface Set
|
||||
map,
|
||||
joinMap,
|
||||
]
|
||||
imports [
|
||||
List,
|
||||
Bool.{ Bool, Eq },
|
||||
Dict.{ Dict },
|
||||
Num.{ Nat },
|
||||
Hash.{ Hash, Hasher },
|
||||
Inspect.{ Inspect, Inspector, InspectFormatter },
|
||||
]
|
||||
imports []
|
||||
|
||||
import List
|
||||
import Bool exposing [Bool, Eq]
|
||||
import Dict exposing [Dict]
|
||||
import Num exposing [Nat]
|
||||
import Hash exposing [Hash, Hasher]
|
||||
import Inspect exposing [Inspect, Inspector, InspectFormatter]
|
||||
|
||||
## Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type))
|
||||
## type which stores a collection of unique values, without any ordering
|
||||
|
@ -137,12 +137,12 @@ interface Str
|
||||
graphemes,
|
||||
contains,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool, Eq },
|
||||
Result.{ Result },
|
||||
List,
|
||||
Num.{ Nat, Num, U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec },
|
||||
]
|
||||
imports []
|
||||
|
||||
import Bool exposing [Bool, Eq]
|
||||
import Result exposing [Result]
|
||||
import List
|
||||
import Num exposing [Nat, Num, U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Dec]
|
||||
|
||||
Utf8ByteProblem : [
|
||||
InvalidStartByte,
|
||||
|
@ -6,40 +6,15 @@ interface TotallyNotJson
|
||||
json,
|
||||
jsonWithOptions,
|
||||
]
|
||||
imports [
|
||||
List,
|
||||
Str,
|
||||
Result.{ Result },
|
||||
Encode,
|
||||
Encode.{
|
||||
Encoder,
|
||||
EncoderFormatting,
|
||||
appendWith,
|
||||
},
|
||||
Decode,
|
||||
Decode.{
|
||||
DecoderFormatting,
|
||||
DecodeResult,
|
||||
},
|
||||
Num.{
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
F32,
|
||||
F64,
|
||||
Nat,
|
||||
Dec,
|
||||
},
|
||||
Bool.{ Bool, Eq },
|
||||
Result,
|
||||
]
|
||||
imports []
|
||||
|
||||
import List
|
||||
import Str
|
||||
import Result exposing [Result]
|
||||
import Encode exposing [Encoder, EncoderFormatting, appendWith]
|
||||
import Decode exposing [DecoderFormatting, DecodeResult]
|
||||
import Num exposing [U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, F32, F64, Nat, Dec]
|
||||
import Bool exposing [Bool, Eq]
|
||||
|
||||
## An opaque type with the `EncoderFormatting` and
|
||||
## `DecoderFormatting` abilities.
|
||||
|
@ -1042,6 +1042,7 @@ fn canonicalize_value_defs<'a>(
|
||||
let mut pending_dbgs = Vec::with_capacity(value_defs.len());
|
||||
let mut pending_expects = Vec::with_capacity(value_defs.len());
|
||||
let mut pending_expect_fx = Vec::with_capacity(value_defs.len());
|
||||
let mut pending_ingested_files = Vec::with_capacity(value_defs.len());
|
||||
|
||||
for loc_pending_def in value_defs {
|
||||
match loc_pending_def.value {
|
||||
@ -1062,6 +1063,10 @@ fn canonicalize_value_defs<'a>(
|
||||
PendingValue::ExpectFx(pending_expect) => {
|
||||
pending_expect_fx.push(pending_expect);
|
||||
}
|
||||
PendingValue::ModuleImport => { /* nothing to do */ }
|
||||
PendingValue::IngestedFileImport(pending_ingested_file) => {
|
||||
pending_ingested_files.push(pending_ingested_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1116,6 +1121,10 @@ fn canonicalize_value_defs<'a>(
|
||||
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
|
||||
}
|
||||
|
||||
for _ in pending_ingested_files {
|
||||
todo!("[modules-revamp]: canonicalize_ingested_file_import");
|
||||
}
|
||||
|
||||
let mut dbgs = ExpectsOrDbgs::with_capacity(pending_dbgs.len());
|
||||
let mut expects = ExpectsOrDbgs::with_capacity(pending_expects.len());
|
||||
let mut expects_fx = ExpectsOrDbgs::with_capacity(pending_expects.len());
|
||||
@ -2750,6 +2759,8 @@ enum PendingValue<'a> {
|
||||
Dbg(PendingExpectOrDbg<'a>),
|
||||
Expect(PendingExpectOrDbg<'a>),
|
||||
ExpectFx(PendingExpectOrDbg<'a>),
|
||||
ModuleImport,
|
||||
IngestedFileImport(ast::IngestedFileImport<'a>),
|
||||
SignatureDefMismatch,
|
||||
}
|
||||
|
||||
@ -2874,6 +2885,44 @@ fn to_pending_value_def<'a>(
|
||||
condition,
|
||||
preceding_comment: *preceding_comment,
|
||||
}),
|
||||
|
||||
ModuleImport(module_import) => {
|
||||
match module_import.exposed {
|
||||
None => {}
|
||||
Some(exposed) if exposed.item.is_empty() => {}
|
||||
Some(exposed) => {
|
||||
for loc_name in exposed.item.items {
|
||||
let exposed_name = loc_name.value.item();
|
||||
let name = exposed_name.as_str();
|
||||
let ident = name.into();
|
||||
|
||||
match env.qualified_lookup(
|
||||
scope,
|
||||
module_import.name.value.name,
|
||||
name,
|
||||
loc_name.region,
|
||||
) {
|
||||
Ok(imported_symbol) => {
|
||||
match scope.import(ident, imported_symbol, loc_name.region) {
|
||||
Ok(()) => {}
|
||||
Err((_shadowed_symbol, _region)) => {
|
||||
internal_error!(
|
||||
"TODO gracefully handle shadowing in imports."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(problem) => {
|
||||
env.problem(Problem::RuntimeError(problem.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PendingValue::ModuleImport
|
||||
}
|
||||
IngestedFileImport(module_import) => PendingValue::IngestedFileImport(*module_import),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,7 +282,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||
dep_idents: &'a IdentIdsByModule,
|
||||
aliases: MutMap<Symbol, Alias>,
|
||||
imported_abilities_state: PendingAbilitiesStore,
|
||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||
initial_scope: MutMap<Ident, (Symbol, Region)>,
|
||||
exposed_symbols: VecSet<Symbol>,
|
||||
symbols_from_requires: &[(Loc<Symbol>, Loc<TypeAnnotation<'a>>)],
|
||||
var_store: &mut VarStore,
|
||||
@ -316,18 +316,13 @@ pub fn canonicalize_module_defs<'a>(
|
||||
|
||||
let mut rigid_variables = RigidVariables::default();
|
||||
|
||||
// Exposed values are treated like defs that appear before any others, e.g.
|
||||
//
|
||||
// imports [Foo.{ bar, baz }]
|
||||
//
|
||||
// ...is basically the same as if we'd added these extra defs at the start of the module:
|
||||
//
|
||||
// bar = Foo.bar
|
||||
// baz = Foo.baz
|
||||
// Iniital scope values are treated like defs that appear before any others.
|
||||
// They include builtin types that are automatically imported, and for a platform
|
||||
// package, the required values from the app.
|
||||
//
|
||||
// Here we essentially add those "defs" to "the beginning of the module"
|
||||
// by canonicalizing them right before we canonicalize the actual ast::Def nodes.
|
||||
for (ident, (symbol, region)) in exposed_imports {
|
||||
for (ident, (symbol, region)) in initial_scope {
|
||||
let first_char = ident.as_inline_str().as_str().chars().next().unwrap();
|
||||
|
||||
if first_char.is_lowercase() {
|
||||
@ -335,7 +330,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||
Ok(()) => {
|
||||
// Add an entry to exposed_imports using the current module's name
|
||||
// as the key; e.g. if this is the Foo module and we have
|
||||
// exposes [Bar.{ baz }] then insert Foo.baz as the key, so when
|
||||
// Bar exposes [baz] then insert Foo.baz as the key, so when
|
||||
// anything references `baz` in this Foo module, it will resolve to Bar.baz.
|
||||
can_exposed_imports.insert(symbol, region);
|
||||
}
|
||||
|
@ -128,6 +128,13 @@ fn desugar_value_def<'a>(
|
||||
preceding_comment: *preceding_comment,
|
||||
}
|
||||
}
|
||||
ModuleImport(roc_parse::ast::ModuleImport {
|
||||
before_name: _,
|
||||
name: _,
|
||||
alias: _,
|
||||
exposed: _,
|
||||
}) => *def,
|
||||
IngestedFileImport(_) => *def,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3682,7 +3682,7 @@ fn constraint_recursive_function(
|
||||
signature_closure_type,
|
||||
ret_type,
|
||||
),
|
||||
_ => todo!("TODO {:?}", (loc_symbol, &signature)),
|
||||
_ => todo!("TODO {:?}", (loc_symbol, types[signature])),
|
||||
};
|
||||
|
||||
let region = loc_function_def.region;
|
||||
|
@ -251,6 +251,12 @@ fn generate_entry_docs(
|
||||
ValueDef::ExpectFx { .. } => {
|
||||
// Don't generate docs for `expect-fx`s
|
||||
}
|
||||
ValueDef::ModuleImport { .. } => {
|
||||
// Don't generate docs for module imports
|
||||
}
|
||||
ValueDef::IngestedFileImport { .. } => {
|
||||
// Don't generate docs for ingested file imports
|
||||
}
|
||||
},
|
||||
Ok(type_index) => match &defs.type_defs[type_index.index()] {
|
||||
TypeDef::Alias {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ use roc_module::symbol::{
|
||||
};
|
||||
use roc_mono::ir::{GlueLayouts, HostExposedLambdaSets, LambdaSetId, Proc, ProcLayout, ProcsBase};
|
||||
use roc_mono::layout::{LayoutCache, STLayoutInterner};
|
||||
use roc_parse::ast::{CommentOrNewline, Defs, TypeAnnotation, ValueDef};
|
||||
use roc_parse::ast::{CommentOrNewline, Defs, TypeAnnotation};
|
||||
use roc_parse::header::{HeaderType, PackageName};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_solve::module::Solved;
|
||||
@ -83,19 +83,12 @@ pub(crate) struct ModuleHeader<'a> {
|
||||
pub(crate) module_id: ModuleId,
|
||||
pub(crate) module_path: PathBuf,
|
||||
pub(crate) is_root_module: bool,
|
||||
pub(crate) exposed_ident_ids: IdentIds,
|
||||
pub(crate) deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
||||
pub(crate) packages: MutMap<&'a str, PackageName<'a>>,
|
||||
pub(crate) imported_modules: MutMap<ModuleId, Region>,
|
||||
pub(crate) package_qualified_imported_modules: MutSet<PackageQualified<'a, ModuleId>>,
|
||||
pub(crate) exposes: Vec<Symbol>,
|
||||
pub(crate) exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||
pub(crate) parse_state: roc_parse::state::State<'a>,
|
||||
pub(crate) header_type: HeaderType<'a>,
|
||||
pub(crate) header_comments: &'a [CommentOrNewline<'a>],
|
||||
pub(crate) symbols_from_requires: Vec<(Loc<Symbol>, Loc<TypeAnnotation<'a>>)>,
|
||||
pub(crate) module_timing: ModuleTiming,
|
||||
pub(crate) defined_values: Vec<ValueDef<'a>>,
|
||||
pub(crate) opt_shorthand: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -190,13 +183,16 @@ pub struct ParsedModule<'a> {
|
||||
pub src: &'a str,
|
||||
pub module_timing: ModuleTiming,
|
||||
pub deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
||||
pub imported_modules: MutMap<ModuleId, Region>,
|
||||
pub exposed_ident_ids: IdentIds,
|
||||
pub exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||
pub parsed_defs: Defs<'a>,
|
||||
pub symbols_from_requires: Vec<(Loc<Symbol>, Loc<TypeAnnotation<'a>>)>,
|
||||
pub header_type: HeaderType<'a>,
|
||||
pub header_comments: &'a [CommentOrNewline<'a>],
|
||||
pub imported_modules: MutMap<ModuleId, Region>,
|
||||
pub package_qualified_imported_modules: MutSet<PackageQualified<'a, ModuleId>>,
|
||||
pub packages: MutMap<&'a str, PackageName<'a>>,
|
||||
pub initial_scope: MutMap<Ident, (Symbol, Region)>,
|
||||
pub exposes: Vec<Symbol>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -162,10 +162,6 @@ impl<'a> Dependencies<'a> {
|
||||
output.insert((dep, Phase::LoadHeader));
|
||||
}
|
||||
|
||||
// to parse and generate constraints, the headers of all dependencies must be loaded!
|
||||
// otherwise, we don't know whether an imported symbol is actually exposed
|
||||
self.add_dependency_help(module_id, dep, Phase::Parse, Phase::LoadHeader);
|
||||
|
||||
// to canonicalize a module, all its dependencies must be canonicalized
|
||||
self.add_dependency(module_id, dep, Phase::CanonicalizeAndConstrain);
|
||||
|
||||
@ -427,10 +423,10 @@ impl<'a> Dependencies<'a> {
|
||||
PrepareStartPhase::Recurse(new)
|
||||
}
|
||||
None => match phase {
|
||||
Phase::LoadHeader => {
|
||||
// this is fine, mark header loading as pending
|
||||
Phase::LoadHeader | Phase::Parse => {
|
||||
// this is fine, mark as pending
|
||||
self.status
|
||||
.insert(Job::Step(module_id, Phase::LoadHeader), Status::Pending);
|
||||
.insert(Job::Step(module_id, phase), Status::Pending);
|
||||
|
||||
PrepareStartPhase::Continue
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
interface Dep1
|
||||
exposes [three, str, Unit, Identity, one, two]
|
||||
imports [Dep3.Blah.{ foo }]
|
||||
imports []
|
||||
|
||||
import Dep3Blah exposing [foo]
|
||||
|
||||
one = 1
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
interface Dep2
|
||||
exposes [one, two, blah]
|
||||
imports [Dep3.Blah.{ foo, bar }]
|
||||
imports []
|
||||
|
||||
import Dep3Blah exposing [foo, bar]
|
||||
|
||||
one = 1
|
||||
|
||||
blah = foo
|
||||
|
||||
two = 2.0
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
interface Dep3.Other
|
||||
exposes [foo, bar]
|
||||
imports []
|
||||
|
||||
foo = "foo from Dep3.Other"
|
||||
bar = "bar from Dep3.Other"
|
@ -1,10 +1,12 @@
|
||||
interface Dep3.Blah
|
||||
interface Dep3Blah
|
||||
exposes [one, two, foo, bar]
|
||||
imports [Dep3.Other]
|
||||
imports []
|
||||
|
||||
import Dep3Other
|
||||
|
||||
one = 1
|
||||
|
||||
two = 2
|
||||
|
||||
foo = "foo from Dep3"
|
||||
bar = Dep3.Other.bar
|
||||
bar = Dep3Other.bar
|
6
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Dep3Other.roc
vendored
Normal file
6
crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Dep3Other.roc
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
interface Dep3Other
|
||||
exposes [foo, bar]
|
||||
imports []
|
||||
|
||||
foo = "foo from Dep3Other"
|
||||
bar = "bar from Dep3Other"
|
@ -1,7 +1,8 @@
|
||||
interface ImportAlias
|
||||
exposes [unit]
|
||||
imports [Dep1]
|
||||
imports []
|
||||
|
||||
import Dep1
|
||||
|
||||
unit : Dep1.Unit
|
||||
unit = Unit
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
interface OneDep
|
||||
exposes [str]
|
||||
imports [Dep3.Blah.{ foo }]
|
||||
imports []
|
||||
|
||||
import Dep3Blah exposing [foo]
|
||||
|
||||
str = foo
|
||||
|
@ -1,6 +1,11 @@
|
||||
interface Primary
|
||||
exposes [blah2, blah3, str, alwaysThree, identity, z, w, succeed, withDefault, yay]
|
||||
imports [Dep1, Dep2.{ two }, Dep3.Blah.{ bar }, Res]
|
||||
imports []
|
||||
|
||||
import Dep1
|
||||
import Dep2 exposing [two]
|
||||
import Dep3Blah exposing [bar]
|
||||
import Res
|
||||
|
||||
blah2 = Dep2.two
|
||||
blah3 = bar
|
||||
|
@ -1,6 +1,9 @@
|
||||
interface WithBuiltins
|
||||
exposes [floatTest, divisionFn, divisionTest, intTest, constantNum, fromDep2, divDep1ByDep2]
|
||||
imports [Dep1, Dep2.{ two }]
|
||||
imports []
|
||||
|
||||
import Dep1
|
||||
import Dep2 exposing [two]
|
||||
|
||||
floatTest = Num.maxF64
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
interface Dep1
|
||||
exposes [three, str, Unit, Identity, one, two]
|
||||
imports [Dep3.Blah.{ foo }]
|
||||
imports []
|
||||
|
||||
import Dep3 exposing [foo]
|
||||
|
||||
one = 1
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
interface Dep2
|
||||
exposes [one, two, blah]
|
||||
imports [Dep3.Blah.{ foo, bar }]
|
||||
imports []
|
||||
|
||||
import Dep3 exposing [foo, bar]
|
||||
|
||||
one = 1
|
||||
|
||||
blah = foo
|
||||
|
||||
two = 2.0
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
interface Dep3.Blah
|
||||
interface Dep3
|
||||
exposes [one, two, foo, bar]
|
||||
imports []
|
||||
|
@ -1,7 +1,8 @@
|
||||
interface ImportAlias
|
||||
exposes [unit]
|
||||
imports [Dep1]
|
||||
imports []
|
||||
|
||||
import Dep1
|
||||
|
||||
unit : Dep1.Unit
|
||||
unit = Unit
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
interface IngestedFile
|
||||
exposes [str]
|
||||
imports ["IngestedFile.roc" as foo : Str]
|
||||
imports []
|
||||
|
||||
import "IngestedFile.roc" as foo : Str
|
||||
|
||||
str = foo
|
||||
|
@ -1,5 +1,7 @@
|
||||
interface IngestedFileBytes
|
||||
exposes [str]
|
||||
imports ["IngestedFileBytes.roc" as foo : List U8]
|
||||
imports []
|
||||
|
||||
import "IngestedFileBytes.roc" as foo : List U8
|
||||
|
||||
str = Str.fromUtf8 foo |> Result.withDefault ""
|
||||
|
@ -1,5 +1,7 @@
|
||||
interface OneDep
|
||||
exposes [str]
|
||||
imports [Dep3.Blah.{ foo }]
|
||||
imports []
|
||||
|
||||
import Dep3 exposing [foo]
|
||||
|
||||
str = foo
|
||||
|
@ -1,6 +1,11 @@
|
||||
interface Primary
|
||||
exposes [blah2, blah3, str, alwaysThree, identity, z, w, succeed, withDefault, yay]
|
||||
imports [Dep1, Dep2.{ two }, Dep3.Blah.{ bar }, Res]
|
||||
imports []
|
||||
|
||||
import Dep1
|
||||
import Dep2 exposing [two]
|
||||
import Dep3 exposing [bar]
|
||||
import Res
|
||||
|
||||
blah2 = Dep2.two
|
||||
blah3 = bar
|
||||
|
@ -1,6 +1,9 @@
|
||||
interface WithBuiltins
|
||||
exposes [floatTest, divisionFn, divisionTest, intTest, constantNum, fromDep2, divDep1ByDep2]
|
||||
imports [Dep1, Dep2.{ two }]
|
||||
imports []
|
||||
|
||||
import Dep1
|
||||
import Dep2 exposing [two]
|
||||
|
||||
floatTest = Num.maxF64
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
interface MissingDep
|
||||
exposes [unit]
|
||||
imports [ThisFileIsMissing]
|
||||
imports []
|
||||
|
||||
import ThisFileIsMissing
|
||||
|
||||
Unit : [Unit]
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
interface MissingIngestedFile
|
||||
exposes [unit]
|
||||
imports ["ThisFileIsMissing" as data: List U8]
|
||||
imports []
|
||||
|
||||
import "ThisFileIsMissing" as data : List U8
|
||||
|
||||
Unit : [Unit]
|
||||
|
||||
|
@ -344,7 +344,9 @@ fn import_transitive_alias() {
|
||||
"Other",
|
||||
indoc!(
|
||||
r"
|
||||
interface Other exposes [empty] imports [RBTree]
|
||||
interface Other exposes [empty] imports []
|
||||
|
||||
import RBTree
|
||||
|
||||
empty : RBTree.RedBlackTree I64 I64
|
||||
empty = RBTree.empty
|
||||
@ -831,7 +833,9 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
|
||||
"Main",
|
||||
indoc!(
|
||||
r"
|
||||
interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
interface Main exposes [twenty, readAge] imports []
|
||||
|
||||
import Age exposing [Age]
|
||||
|
||||
twenty = @Age 20
|
||||
|
||||
@ -851,13 +855,13 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
|
||||
|
||||
The unwrapped opaque type Age referenced here:
|
||||
|
||||
3│ twenty = @Age 20
|
||||
5│ twenty = @Age 20
|
||||
^^^^
|
||||
|
||||
is imported from another module:
|
||||
|
||||
1│ interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
^^^
|
||||
3│ import Age exposing [Age]
|
||||
^^^
|
||||
|
||||
Note: Opaque types can only be wrapped and unwrapped in the module they are defined in!
|
||||
|
||||
@ -865,24 +869,15 @@ fn opaque_wrapped_unwrapped_outside_defining_module() {
|
||||
|
||||
The unwrapped opaque type Age referenced here:
|
||||
|
||||
5│ readAge = \@Age n -> n
|
||||
7│ readAge = \@Age n -> n
|
||||
^^^^
|
||||
|
||||
is imported from another module:
|
||||
|
||||
1│ interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
^^^
|
||||
3│ import Age exposing [Age]
|
||||
^^^
|
||||
|
||||
Note: Opaque types can only be wrapped and unwrapped in the module they are defined in!
|
||||
|
||||
── UNUSED IMPORT in tmp/opaque_wrapped_unwrapped_outside_defining_module/Main ──
|
||||
|
||||
Nothing from Age is used in this module.
|
||||
|
||||
1│ interface Main exposes [twenty, readAge] imports [Age.{ Age }]
|
||||
^^^^^^^^^^^
|
||||
|
||||
Since Age isn't used, you don't need to import it.
|
||||
"
|
||||
),
|
||||
"\n{}",
|
||||
@ -962,9 +957,11 @@ fn import_builtin_in_platform_and_check_app() {
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports [Str]
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
import Str
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
||||
"#
|
||||
@ -1029,7 +1026,9 @@ fn module_cyclic_import_itself() {
|
||||
"Age",
|
||||
indoc!(
|
||||
r"
|
||||
interface Age exposes [] imports [Age]
|
||||
interface Age exposes [] imports []
|
||||
|
||||
import Age
|
||||
"
|
||||
),
|
||||
)];
|
||||
@ -1066,7 +1065,8 @@ fn module_cyclic_import_transitive() {
|
||||
"Age",
|
||||
indoc!(
|
||||
r"
|
||||
interface Age exposes [] imports [Person]
|
||||
interface Age exposes [] imports []
|
||||
import Person
|
||||
"
|
||||
),
|
||||
),
|
||||
@ -1074,7 +1074,8 @@ fn module_cyclic_import_transitive() {
|
||||
"Person",
|
||||
indoc!(
|
||||
r"
|
||||
interface Person exposes [] imports [Age]
|
||||
interface Person exposes [] imports []
|
||||
import Age
|
||||
"
|
||||
),
|
||||
),
|
||||
@ -1106,45 +1107,3 @@ fn module_cyclic_import_transitive() {
|
||||
err
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_module_has_incorrect_name() {
|
||||
let modules = vec![
|
||||
(
|
||||
"Dep/Foo.roc",
|
||||
indoc!(
|
||||
r"
|
||||
interface Foo exposes [] imports []
|
||||
"
|
||||
),
|
||||
),
|
||||
(
|
||||
"I.roc",
|
||||
indoc!(
|
||||
r"
|
||||
interface I exposes [] imports [Dep.Foo]
|
||||
"
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
let err = multiple_modules("nested_module_has_incorrect_name", modules).unwrap_err();
|
||||
assert_eq!(
|
||||
err,
|
||||
indoc!(
|
||||
r"
|
||||
── INCORRECT MODULE NAME in tmp/nested_module_has_incorrect_name/Dep/Foo.roc ───
|
||||
|
||||
This module has a different name than I expected:
|
||||
|
||||
1│ interface Foo exposes [] imports []
|
||||
^^^
|
||||
|
||||
Based on the nesting and use of this module, I expect it to have name
|
||||
|
||||
Dep.Foo"
|
||||
),
|
||||
"\n{}",
|
||||
err
|
||||
);
|
||||
}
|
||||
|
@ -168,7 +168,6 @@ macro_rules! keywords {
|
||||
|
||||
keywords! {
|
||||
ExposesKeyword => "exposes",
|
||||
ImportsKeyword => "imports",
|
||||
WithKeyword => "with",
|
||||
GeneratesKeyword => "generates",
|
||||
PackageKeyword => "package",
|
||||
@ -176,6 +175,8 @@ keywords! {
|
||||
RequiresKeyword => "requires",
|
||||
ProvidesKeyword => "provides",
|
||||
ToKeyword => "to",
|
||||
// [modules-revamp] TODO: Remove
|
||||
ImportsKeyword => "imports",
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -622,6 +622,12 @@ impl IterTokens for ValueDef<'_> {
|
||||
} => (onetoken(Token::Comment, *preceding_comment, arena).into_iter())
|
||||
.chain(condition.iter_tokens(arena))
|
||||
.collect_in(arena),
|
||||
ValueDef::ModuleImport(..) => {
|
||||
todo!("[modules-revamp]")
|
||||
}
|
||||
ValueDef::IngestedFileImport(..) => {
|
||||
todo!("[modules-revamp]")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,12 @@ impl ReplState {
|
||||
ValueDef::ExpectFx { .. } => {
|
||||
todo!("handle receiving an `expect-fx` - what should the repl do for that?")
|
||||
}
|
||||
ValueDef::ModuleImport(_) => {
|
||||
todo!("handle importing a module from the REPL")
|
||||
}
|
||||
ValueDef::IngestedFileImport(_) => {
|
||||
todo!("handle ingesting a file from the REPL")
|
||||
}
|
||||
}
|
||||
}
|
||||
ParseOutcome::TypeDef(TypeDef::Alias {
|
||||
|
Loading…
Reference in New Issue
Block a user