diff --git a/kclvm/error/src/diagnostic.rs b/kclvm/error/src/diagnostic.rs index 19779afaf..c15c14d4f 100644 --- a/kclvm/error/src/diagnostic.rs +++ b/kclvm/error/src/diagnostic.rs @@ -136,6 +136,12 @@ impl Diagnostic { pub type Range = (Position, Position); +/// Returns a dummy range whose filename is empty, line is 1 and column is None. +#[inline] +pub fn dummy_range() -> Range { + (Position::dummy_pos(), Position::dummy_pos()) +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Message { pub range: Range, diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap index d434b79b8..341ed1a82 100644 --- a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_1.snap @@ -61,6 +61,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: false, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "type", @@ -70,6 +82,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "required", @@ -79,6 +103,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: BOOL, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "default", @@ -88,6 +124,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: ANY, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "help", @@ -97,6 +145,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, ], self_ty: None, diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap index e43dc4009..8a06600bc 100644 --- a/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__builtin_call_2.snap @@ -17,6 +17,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: false, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "type", @@ -26,6 +38,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "required", @@ -35,6 +59,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: BOOL, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "default", @@ -44,6 +80,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: ANY, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "help", @@ -53,6 +101,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, ], self_ty: None, @@ -122,6 +182,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: false, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "type", @@ -131,6 +203,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "required", @@ -140,6 +224,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: BOOL, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "default", @@ -149,6 +245,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: ANY, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "help", @@ -158,6 +266,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, ], self_ty: None, @@ -263,6 +383,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: false, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "type", @@ -272,6 +404,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "required", @@ -281,6 +425,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: BOOL, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "default", @@ -290,6 +446,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: ANY, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "help", @@ -299,6 +467,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: STR, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, ], self_ty: None, diff --git a/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap b/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap index 6d64a6a42..14c4e6a0c 100644 --- a/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap +++ b/kclvm/loader/src/snapshots/kclvm_loader__tests__import_stmt_0.snap @@ -388,6 +388,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: UNION, }, has_default: false, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, Parameter { name: "e", @@ -397,6 +409,18 @@ expression: "format!(\"{:#?}\", p.symbols.values())" flags: FLOAT, }, has_default: true, + range: ( + Position { + filename: "", + line: 1, + column: None, + }, + Position { + filename: "", + line: 1, + column: None, + }, + ), }, ], self_ty: None, diff --git a/kclvm/sema/src/builtin/decorator.rs b/kclvm/sema/src/builtin/decorator.rs index 6a453bfed..46d84bff3 100644 --- a/kclvm/sema/src/builtin/decorator.rs +++ b/kclvm/sema/src/builtin/decorator.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; use crate::ty::{Parameter, Type}; @@ -28,16 +29,19 @@ register_decorator! { name: "version".to_string(), ty: Arc::new(Type::STR), has_default: true, + range: dummy_range(), }, Parameter { name: "reason".to_string(), ty: Arc::new(Type::STR), has_default: true, + range: dummy_range(), }, Parameter { name: "strict".to_string(), ty: Arc::new(Type::BOOL), has_default: true, + range: dummy_range(), }, ], r#"This decorator is used to get the deprecation message according to the wrapped key-value pair."#, diff --git a/kclvm/sema/src/builtin/mod.rs b/kclvm/sema/src/builtin/mod.rs index b8c42c5bf..18491617d 100644 --- a/kclvm/sema/src/builtin/mod.rs +++ b/kclvm/sema/src/builtin/mod.rs @@ -8,6 +8,7 @@ pub mod system_module; use std::sync::Arc; use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; use crate::ty::{Parameter, Type}; @@ -42,26 +43,31 @@ register_builtin! { name: "key".to_string(), ty: Arc::new(Type::STR), has_default: false, + range: dummy_range(), }, Parameter { name: "type".to_string(), ty: Arc::new(Type::STR), has_default: true, + range: dummy_range(), }, Parameter { name: "required".to_string(), ty: Arc::new(Type::BOOL), has_default: true, + range: dummy_range(), }, Parameter { name: "default".to_string(), ty: Arc::new(Type::ANY), has_default: true, + range: dummy_range(), }, Parameter { name: "help".to_string(), ty: Arc::new(Type::STR), has_default: true, + range: dummy_range(), }, ], "Return the top level argument by the key", @@ -87,11 +93,13 @@ end: string appended after the last value, default a newline."#, name: "a".to_string(), ty: Arc::new(Type::INT), has_default: false, + range: dummy_range(), }, Parameter { name: "b".to_string(), ty: Arc::new(Type::INT), has_default: false, + range: dummy_range(), }, ], "Check if the modular result of a and b is 0.", @@ -106,6 +114,7 @@ end: string appended after the last value, default a newline."#, name: "inval".to_string(), ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + range: dummy_range(), }, ], "Check if a list has duplicated elements", @@ -120,6 +129,7 @@ end: string appended after the last value, default a newline."#, name: "inval".to_string(), ty: Type::iterable(), has_default: false, + range: dummy_range(), }, ], "Return the length of a value.", @@ -134,6 +144,7 @@ end: string appended after the last value, default a newline."#, name: "inval".to_string(), ty: Arc::new(Type::ANY), has_default: false, + range: dummy_range(), }, ], "Return the absolute value of the argument.", @@ -148,6 +159,7 @@ end: string appended after the last value, default a newline."#, name: "inval".to_string(), ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + range: dummy_range(), }, ], r#"Return True if bool(x) is True for all values x in the iterable. @@ -164,6 +176,7 @@ If the iterable is empty, return True."#, name: "inval".to_string(), ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + range: dummy_range(), }, ], r#"Return True if bool(x) is True for any x in the iterable. @@ -180,6 +193,7 @@ If the iterable is empty, return False."#, name: "number".to_string(), ty: Arc::new(Type::INT), has_default: false, + range: dummy_range(), }, ], "Return the hexadecimal representation of an integer.", @@ -194,6 +208,7 @@ If the iterable is empty, return False."#, name: "number".to_string(), ty: Arc::new(Type::INT), has_default: false, + range: dummy_range(), }, ], "Return the binary representation of an integer.", @@ -208,6 +223,7 @@ If the iterable is empty, return False."#, name: "number".to_string(), ty: Arc::new(Type::INT), has_default: false, + range: dummy_range(), }, ], "Return the octal representation of an integer.", @@ -222,6 +238,7 @@ If the iterable is empty, return False."#, name: "c".to_string(), ty: Arc::new(Type::STR), has_default: false, + range: dummy_range(), }, ], "Return the Unicode code point for a one-character string.", @@ -236,11 +253,13 @@ If the iterable is empty, return False."#, name: "inval".to_string(), ty: Type::iterable(), has_default: false, + range: dummy_range(), }, Parameter { name: "reverse".to_string(), ty: Arc::new(Type::BOOL), has_default: true, + range: dummy_range(), }, ], r#"Return a new list containing all items from the iterable in ascending order. @@ -258,16 +277,19 @@ flag can be set to request the result in descending order."#, name: "start".to_string(), ty: Arc::new(Type::INT), has_default: true, + range: dummy_range(), }, Parameter { name: "stop".to_string(), ty: Arc::new(Type::INT), has_default: true, + range: dummy_range(), }, Parameter { name: "step".to_string(), ty: Arc::new(Type::INT), has_default: true, + range: dummy_range(), }, ], r#"Return the range of a value."#, @@ -304,11 +326,13 @@ return the smallest argument."#, name: "iterable".to_string(), ty: Type::list_ref(Arc::new(Type::ANY)), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Arc::new(Type::ANY), has_default: true, + range: dummy_range(), }, ], r#"When the iterable is empty, return the start value. This function is @@ -325,16 +349,19 @@ non-numeric types."#, name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, Parameter { name: "y".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, Parameter { name: "z".to_string(), ty: Type::number(), has_default: true, + range: dummy_range(), }, ], r#"Equivalent to `x ** y` (with two arguments) or `x ** y % z` (with three arguments) @@ -352,11 +379,13 @@ invoked using the three argument form."#, name: "number".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, Parameter { name: "ndigits".to_string(), ty: Arc::new(Type::INT), has_default: true, + range: dummy_range(), }, ], r#"Round a number to a given precision in decimal digits. @@ -385,11 +414,13 @@ argument."#, name: "number".to_string(), ty: Arc::new(Type::ANY), has_default: false, + range: dummy_range(), }, Parameter { name: "base".to_string(), ty: Arc::new(Type::INT), has_default: true, + range: dummy_range(), }, ], r#"Convert a number or string to an integer, or return 0 if no arguments @@ -405,6 +436,7 @@ are given. For floating point numbers, this truncates towards zero."#, name: "number".to_string(), ty: Arc::new(Type::ANY), has_default: false, + range: dummy_range(), }, ], r#"Convert a string or number to a floating point number, if possible."#, @@ -419,6 +451,7 @@ are given. For floating point numbers, this truncates towards zero."#, name: "x".to_string(), ty: Arc::new(Type::ANY), has_default: true, + range: dummy_range(), }, ], r#"Returns True when the argument x is true, False otherwise. @@ -435,6 +468,7 @@ The class bool is a subclass of the class int, and cannot be subclassed."#, name: "x".to_string(), ty: Arc::new(Type::ANY), has_default: true, + range: dummy_range(), }, ], r#"Create a new string object from the given object. @@ -452,6 +486,7 @@ given encoding and error handler."#, name: "x".to_string(), ty: Arc::new(Type::ANY), has_default: true, + range: dummy_range(), }, ], r#"Built-in list function, which can convert other data types or construct a list. @@ -469,6 +504,7 @@ The argument must be an iterable if specified."#, name: "x".to_string(), ty: Arc::new(Type::ANY), has_default: true, + range: dummy_range(), }, ], r#"Built-in dict function. @@ -485,11 +521,13 @@ If no argument is given, the constructor creates a new empty dict."#, name: "x".to_string(), ty: Arc::new(Type::ANY), has_default: false, + range: dummy_range(), }, Parameter { name: "full_name".to_string(), ty: Arc::new(Type::BOOL), has_default: true, + range: dummy_range(), }, ], r#"Return the type of the object"#, diff --git a/kclvm/sema/src/builtin/string.rs b/kclvm/sema/src/builtin/string.rs index 1778afc0d..f9e3770c3 100644 --- a/kclvm/sema/src/builtin/string.rs +++ b/kclvm/sema/src/builtin/string.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; use crate::ty::{Parameter, Type}; @@ -33,16 +34,19 @@ register_string_member! { name: "sub".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return the number of non-overlapping occurrences of substring sub in the range [start, end]. Optional arguments start and end are interpreted as in slice notation."#, @@ -57,16 +61,19 @@ register_string_member! { name: "val".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return True if the string ends with the specified suffix, otherwise return False. suffix can also be a tuple of suffixes to look for. With optional start, test beginning at that position. With optional end, stop comparing at that position."#, @@ -81,16 +88,19 @@ register_string_member! { name: "sub".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return the lowest index in the string where substring sub is found within the slice s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 if sub is not found."#, @@ -113,16 +123,19 @@ register_string_member! { name: "sub".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Like str.find(), but raise an error when the substring is not found."#, @@ -193,6 +206,7 @@ register_string_member! { name: "iter".to_string(), ty: Type::list_ref(Type::any_ref()), has_default: false, + range: dummy_range(), }, ], r#"Return a string which is the concatenation of the strings in iterable. An error will be raised if there are any non-string values in iterable. The separator between elements is the string providing this method."#, @@ -223,6 +237,7 @@ register_string_member! { name: "chars".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a copy of the string with leading characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix; rather, all combinations of its values are stripped:"#, @@ -237,6 +252,7 @@ register_string_member! { name: "chars".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped:"#, @@ -251,16 +267,19 @@ register_string_member! { name: "old".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "new".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "count".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.Return a copy of the string with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced."#, @@ -275,6 +294,7 @@ register_string_member! { name: "prefix".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"If the string starts with the prefix string, return string[len(prefix):]. Otherwise, return a copy of the original string."#, @@ -289,6 +309,7 @@ register_string_member! { name: "suffix".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. Otherwise, return a copy of the original string."#, @@ -303,16 +324,19 @@ register_string_member! { name: "sub".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return the highest index in the string where substring sub is found, such that sub is contained within s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 on failure."#, @@ -327,16 +351,19 @@ register_string_member! { name: "sub".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Like rfind() but raises ValueError when the substring sub is not found."#, @@ -351,11 +378,13 @@ register_string_member! { name: "sep".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "maxsplit".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done, the rightmost ones. If sep is not specified or None, any whitespace string is a separator. Except for splitting from the right, rsplit() behaves like split() which is described in detail below."#, @@ -370,11 +399,13 @@ register_string_member! { name: "sep".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "maxsplit".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). If maxsplit is not specified or -1, then there is no limit on the number of splits (all possible splits are made)."#, @@ -389,6 +420,7 @@ register_string_member! { name: "keepends".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a list of the lines in the string, breaking at line boundaries. Line breaks are not included in the resulting list unless keepends is given and true."#, @@ -403,16 +435,19 @@ register_string_member! { name: "val".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "start".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "end".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return True if string starts with the prefix, otherwise return False. prefix can also be a tuple of prefixes to look for. With optional start, test string beginning at that position. With optional end, stop comparing string at that position."#, @@ -427,6 +462,7 @@ register_string_member! { name: "chars".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a copy of the string with the leading and trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a prefix or suffix; rather, all combinations of its values are stripped:"#, diff --git a/kclvm/sema/src/builtin/system_module.rs b/kclvm/sema/src/builtin/system_module.rs index 5e439bbfa..0b2abf430 100644 --- a/kclvm/sema/src/builtin/system_module.rs +++ b/kclvm/sema/src/builtin/system_module.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use crate::ty::{Parameter, Type, TypeRef}; use indexmap::IndexMap; +use kclvm_error::diagnostic::dummy_range; use once_cell::sync::Lazy; // ------------------------------ @@ -32,11 +33,13 @@ register_base64_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encode the string `value` using the codec registered for encoding."#, @@ -51,11 +54,13 @@ register_base64_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Decode the string `value` using the codec registered for encoding."#, @@ -90,6 +95,7 @@ register_net_member! { name: "ip_end_point".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Split the `host` and `port` from the `ip_end_point`."#, @@ -104,11 +110,13 @@ register_net_member! { name: "host".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "port".to_string(), ty: Type::union_ref(&[Type::int_ref(), Type::str_ref()]), has_default: false, + range: dummy_range(), }, ], r#"Merge the `host` and `port`."#, @@ -123,6 +131,7 @@ register_net_member! { name: "name".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return Fully Qualified Domain Name (FQDN)."#, @@ -137,6 +146,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Parse ip to a real IP address."#, @@ -151,6 +161,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Get the IP string."#, @@ -165,6 +176,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Get the IP4 form of ip."#, @@ -179,6 +191,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Get the IP16 form of ip."#, @@ -193,6 +206,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a IPv4 one."#, @@ -207,6 +221,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a valid ip address."#, @@ -221,6 +236,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a loopback one."#, @@ -235,6 +251,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a multicast one."#, @@ -249,6 +266,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a interface, local and multicast one."#, @@ -263,6 +281,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a link local and multicast one."#, @@ -277,6 +296,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a link local and unicast one."#, @@ -291,6 +311,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a global and unicast one."#, @@ -305,6 +326,7 @@ register_net_member! { name: "ip".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether ip is a unspecified one."#, @@ -339,11 +361,13 @@ register_manifests_member! { name: "values".to_string(), ty: Type::any_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "opts".to_string(), ty: Type::dict_ref(Type::str_ref(), Type::any_ref()), has_default: true, + range: dummy_range(), }, ], r#"This function is used to serialize the KCL object list into YAML output with the --- separator. It has two parameters: @@ -385,6 +409,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the ceiling of `x` as an Integral. This is the smallest integer >= `x`."#, @@ -399,6 +424,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `x`!. Raise a error if `x` is negative or non-integral."#, @@ -413,6 +439,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the floor of `x` as an Integral. This is the largest integer <= `x`."#, @@ -427,11 +454,13 @@ register_math_member! { name: "a".to_string(), ty: Type::int_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "b".to_string(), ty: Type::int_ref(), has_default: false, + range: dummy_range(), }, ], r#"Return the greatest common divisor of `x` and `y`."#, @@ -446,6 +475,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `True` if `x` is neither an infinity nor a NaN, and `False` otherwise."#, @@ -460,6 +490,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `True` if `x` is a positive or negative infinity, and `False` otherwise."#, @@ -474,6 +505,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `True` if `x` is a NaN (not a number), and `False` otherwise."#, @@ -488,6 +520,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the fractional and integer parts of `x`. Both results carry the sign of `x` and are floats."#, @@ -502,6 +535,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `e` raised to the power of `x`."#, @@ -516,6 +550,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `exp(x) - 1`. This function avoids the loss of precision involved in the direct evaluation of `exp(x) - 1` for small `x`."#, @@ -530,11 +565,13 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, Parameter { name: "e".to_string(), ty: Type::float_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return the logarithm of `x` to the base `e`."#, @@ -549,6 +586,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the natural logarithm of `1+x` (base `e`). The result is computed in a way which is accurate for `x` near zero."#, @@ -563,6 +601,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the base 2 logarithm of x."#, @@ -577,6 +616,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the base 10 logarithm of `x`."#, @@ -591,11 +631,13 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, Parameter { name: "y".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return `x**y` (`x` to the power of `y`)."#, @@ -610,6 +652,7 @@ register_math_member! { name: "x".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Return the square root of `x`."#, @@ -696,21 +739,25 @@ register_regex_member! { name: "string".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "replace".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "count".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return the string obtained by replacing the leftmost non-overlapping occurrences of the pattern in string by the replacement."#, @@ -725,11 +772,13 @@ register_regex_member! { name: "string".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Try to apply the pattern at the start of the string, returning a bool value `True` if any match was found, or `False` if no match was found."#, @@ -744,6 +793,7 @@ register_regex_member! { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Compile a regular expression pattern, returning a bool value denoting whether the pattern is valid."#, @@ -758,11 +808,13 @@ register_regex_member! { name: "string".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Return a list of all non-overlapping matches in the string."#, @@ -777,11 +829,13 @@ register_regex_member! { name: "string".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Scan through string looking for a match to the pattern, returning a bool value `True` if any match was found, or `False` if no match was found."#, @@ -796,16 +850,19 @@ register_regex_member! { name: "string".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "maxsplit".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, ], r#"Return a list composed of words from the string, splitting up to a maximum of `maxsplit` times using `pattern` as the separator."#, @@ -840,21 +897,25 @@ register_yaml_member! { name: "data".to_string(), ty: Type::any_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "sort_keys".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_private".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_none".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Serialize a KCL object `data` to a YAML formatted str."#, @@ -869,21 +930,25 @@ register_yaml_member! { name: "data".to_string(), ty: Type::list_ref(Type::any_ref()), has_default: false, + range: dummy_range(), }, Parameter { name: "sort_keys".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_private".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_none".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Serialize a sequence of KCL objects into a YAML stream str."#, @@ -898,6 +963,7 @@ register_yaml_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Deserialize `value` (a string instance containing a YAML document) to a KCL object."#, @@ -912,6 +978,7 @@ register_yaml_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Parse all YAML documents in a stream and produce corresponding KCL objects."#, @@ -926,26 +993,31 @@ register_yaml_member! { name: "data".to_string(), ty: Type::any_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "filename".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "sort_keys".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_private".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_none".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Serialize a KCL object `data` to a YAML formatted str and write it into the file `filename`."#, @@ -960,26 +1032,31 @@ register_yaml_member! { name: "data".to_string(), ty: Type::list_ref(Type::any_ref()), has_default: false, + range: dummy_range(), }, Parameter { name: "filename".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "sort_keys".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_private".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_none".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Serialize a sequence of KCL objects into a YAML stream str and write it into the file `filename`."#, @@ -994,6 +1071,7 @@ register_yaml_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Validate whether the given string is a valid YAML or YAML stream document."#, @@ -1028,26 +1106,31 @@ register_json_member! { name: "data".to_string(), ty: Type::any_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "sort_keys".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "indent".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_private".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_none".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Serialize a KCL object `data` to a JSON formatted str."#, @@ -1062,6 +1145,7 @@ register_json_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Deserialize `value` (a string instance containing a JSON document) to a KCL object."#, @@ -1076,31 +1160,37 @@ register_json_member! { name: "data".to_string(), ty: Type::any_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "filename".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "sort_keys".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "indent".to_string(), ty: Type::int_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_private".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, Parameter { name: "ignore_none".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Serialize a KCL object `data` to a YAML formatted str and write it into the file `filename`."#, @@ -1115,6 +1205,7 @@ register_json_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Validate whether the given string is a valid JSON"#, @@ -1149,11 +1240,13 @@ register_crypto_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encrypt the string `value` using `MD5` and the codec registered for encoding."#, @@ -1168,11 +1261,13 @@ register_crypto_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encrypt the string `value` using `SHA1` and the codec registered for encoding."#, @@ -1187,11 +1282,13 @@ register_crypto_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encrypt the string `value` using `SHA224` and the codec registered for encoding."#, @@ -1206,11 +1303,13 @@ register_crypto_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encrypt the string `value` using `SHA256` and the codec registered for encoding."#, @@ -1225,11 +1324,13 @@ register_crypto_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encrypt the string `value` using `SHA384` and the codec registered for encoding."#, @@ -1244,11 +1345,13 @@ register_crypto_member! { name: "value".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "encoding".to_string(), ty: Type::str_ref(), has_default: true, + range: dummy_range(), }, ], r#"Encrypt the string `value` using `SHA512` and the codec registered for encoding."#, @@ -1271,6 +1374,7 @@ register_crypto_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Calculate the SHA256 hash of the file `filepath`."#, @@ -1338,6 +1442,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `n` suffix."#, @@ -1352,6 +1457,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `u` suffix."#, @@ -1366,6 +1472,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `m` suffix."#, @@ -1380,6 +1487,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `K` suffix."#, @@ -1394,6 +1502,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `M` suffix."#, @@ -1408,6 +1517,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `G` suffix."#, @@ -1422,6 +1532,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `T` suffix."#, @@ -1436,6 +1547,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `P` suffix."#, @@ -1450,6 +1562,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `Ki` suffix."#, @@ -1464,6 +1577,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `Mi` suffix."#, @@ -1478,6 +1592,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `Gi` suffix."#, @@ -1492,6 +1607,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `Ti` suffix."#, @@ -1506,6 +1622,7 @@ register_units_member! { name: "num".to_string(), ty: Type::number(), has_default: false, + range: dummy_range(), }, ], r#"Int literal to string with `Pi` suffix."#, @@ -1540,6 +1657,7 @@ register_collection_member! { name: "num".to_string(), ty: Type::list_ref(Type::any_ref()), has_default: false, + range: dummy_range(), }, ], r#"Union all object to one object."#, @@ -1574,6 +1692,7 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Read the file content from path"#, @@ -1588,6 +1707,7 @@ register_file_member! { name: "pattern".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Find all paths that match a pattern"#, @@ -1626,6 +1746,7 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Whether this file path exists. Returns true if the path points at an existing entity. This function will traverse symbolic links to query information about the destination file."#, @@ -1640,6 +1761,7 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Returns the canonical, absolute form of the path with all intermediate components normalized and symbolic links resolved."#, @@ -1654,11 +1776,13 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "content".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Append content to a file at the specified path. If the file doesn't exist, it will be created."#, @@ -1673,11 +1797,13 @@ register_file_member! { name: "directory".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "exists".to_string(), ty: Type::bool_ref(), has_default: true, + range: dummy_range(), }, ], r#"Create a new directory at the specified path if it doesn't already exist."#, @@ -1692,6 +1818,7 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Delete a file or an empty directory at the specified path."#, @@ -1706,11 +1833,13 @@ register_file_member! { name: "src".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "dest".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Copy a file or directory from the source path to the destination path."#, @@ -1725,11 +1854,13 @@ register_file_member! { name: "src".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "dest".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Move a file or directory from the source path to the destination path."#, @@ -1744,6 +1875,7 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Get the size of a file at the specified path."#, @@ -1758,11 +1890,13 @@ register_file_member! { name: "filepath".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "content".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Write content to a file at the specified path. If the file doesn't exist, it will be created. If it does exist, its content will be replaced."#, @@ -1777,6 +1911,7 @@ register_file_member! { name: "key".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Read the environment variable key from the current process."#, @@ -1811,11 +1946,13 @@ register_template_member! { name: "template".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, Parameter { name: "data".to_string(), ty: Type::dict_ref(Type::str_ref(), Type::any_ref()), has_default: true, + range: dummy_range(), }, ], r#"Applies a parsed template to the specified data object and returns the string output. See https://handlebarsjs.com/ for more documents and examples."#, @@ -1830,6 +1967,7 @@ register_template_member! { name: "data".to_string(), ty: Type::str_ref(), has_default: false, + range: dummy_range(), }, ], r#"Replaces the characters `&"<>` with the equivalent html / xml entities."#, @@ -1864,6 +2002,7 @@ register_runtime_member! { name: "func".to_string(), ty: Arc::new(Type::function(None, Type::any_ref(), &[], "", false, None)), has_default: false, + range: dummy_range(), }, ], r#"Executes the provided function and catches any potential runtime errors. Returns undefined if execution is successful, otherwise returns an error message in case of a runtime panic."#, diff --git a/kclvm/sema/src/resolver/arg.rs b/kclvm/sema/src/resolver/arg.rs index 6d2596d0d..265e9a8a9 100644 --- a/kclvm/sema/src/resolver/arg.rs +++ b/kclvm/sema/src/resolver/arg.rs @@ -5,6 +5,7 @@ use indexmap::IndexSet; use kclvm_ast::ast; use kclvm_ast::pos::GetPos; +use kclvm_error::diagnostic::Range; use crate::ty::TypeRef; @@ -34,11 +35,40 @@ impl<'ctx> Resolver<'ctx> { func_ty: &FunctionType, ) { let func_name = self.get_func_name(&func.node); - let arg_types = self.exprs(args); - let mut kwarg_types: Vec<(String, TypeRef)> = vec![]; let mut check_table: IndexSet = IndexSet::default(); let mut prev_kw_pos = None; - for kw in kwargs { + for (i, arg) in args.iter().enumerate() { + match func_ty.params.get(i) { + Some(param) => { + self.upgrade_type_for_expr( + param.ty.clone(), + arg, + arg.get_span_pos(), + Some(param.range.clone()), + ); + } + None => { + // If the parameter has not a expected type, just check the argument type + // and do not upgrade the type. + self.expr(arg); + if !func_ty.is_variadic { + self.handler.add_compile_error_with_suggestions( + &format!( + "{} takes {} but {} were given", + func_name, + UnitUsize(func_ty.params.len(), "positional argument".to_string()) + .into_string_with_unit(), + args.len(), + ), + args[i].get_span_pos(), + Some(vec![]), + ); + break; + } + } + }; + } + for (i, kw) in kwargs.iter().enumerate() { if !kw.node.arg.node.names.is_empty() { let previous_pos = if let Some(prev_pos) = prev_kw_pos { prev_pos @@ -55,11 +85,45 @@ impl<'ctx> Resolver<'ctx> { ); } check_table.insert(arg_name.to_string()); - let arg_value_type = self.expr_or_any_type(&kw.node.value); - self.node_ty_map - .borrow_mut() - .insert(self.get_node_key(kw.id.clone()), arg_value_type.clone()); - kwarg_types.push((arg_name.to_string(), arg_value_type.clone())); + + if !func_ty + .params + .iter() + .map(|p| p.name.clone()) + .any(|x| x == *arg_name) + && !func_ty.is_variadic + { + let (suggs, msg) = self.get_arg_kw_err_suggestion_from_name(arg_name, func_ty); + self.handler.add_compile_error_with_suggestions( + &format!( + "{} got an unexpected keyword argument '{}'{}", + func_name, arg_name, msg + ), + kwargs[i].node.arg.get_span_pos(), + Some(suggs), + ); + } + + let expected_types_and_ranges: Vec<(TypeRef, Range)> = func_ty + .params + .iter() + .filter(|p| p.name == *arg_name) + .map(|p| (p.ty.clone(), p.range.clone())) + .collect(); + + if let Some((expected_ty, def_range)) = expected_types_and_ranges.first() { + if let Some(value) = &kw.node.value { + let arg_value_type = self.upgrade_type_for_expr( + expected_ty.clone(), + value, + value.get_span_pos(), + Some(def_range.clone()), + ); + self.node_ty_map + .borrow_mut() + .insert(self.get_node_key(kw.id.clone()), arg_value_type.clone()); + } + } } else { self.handler .add_compile_error(&format!("missing argument"), kw.get_span_pos()); @@ -91,78 +155,6 @@ impl<'ctx> Resolver<'ctx> { ); } } - // Do normal argument type check - for (i, ty) in arg_types.iter().enumerate() { - let expected_ty = match func_ty.params.get(i) { - Some(param) => param.ty.clone(), - None => { - if !func_ty.is_variadic { - self.handler.add_compile_error_with_suggestions( - &format!( - "{} takes {} but {} were given", - func_name, - UnitUsize(func_ty.params.len(), "positional argument".to_string()) - .into_string_with_unit(), - args.len(), - ), - args[i].get_span_pos(), - Some(vec![]), - ); - } - return; - } - }; - self.must_assignable_to( - ty.clone(), - expected_ty.clone(), - args[i].get_span_pos(), - None, - ); - - let upgrade_schema_type = self.upgrade_dict_to_schema( - ty.clone(), - expected_ty.clone(), - &args[i].get_span_pos(), - ); - self.node_ty_map.borrow_mut().insert( - self.get_node_key(args.get(i).unwrap().id.clone()), - upgrade_schema_type.clone(), - ); - } - // Do keyword argument type check - for (i, (arg_name, kwarg_ty)) in kwarg_types.iter().enumerate() { - if !func_ty - .params - .iter() - .map(|p| p.name.clone()) - .any(|x| x == *arg_name) - && !func_ty.is_variadic - { - let (suggs, msg) = self.get_arg_kw_err_suggestion_from_name(arg_name, func_ty); - self.handler.add_compile_error_with_suggestions( - &format!( - "{} got an unexpected keyword argument '{}'{}", - func_name, arg_name, msg - ), - kwargs[i].node.arg.get_span_pos(), - Some(suggs), - ); - } - let expected_types: Vec = func_ty - .params - .iter() - .filter(|p| p.name == *arg_name) - .map(|p| p.ty.clone()) - .collect(); - if !expected_types.is_empty() { - self.must_assignable_to( - kwarg_ty.clone(), - expected_types[0].clone(), - kwargs[i].get_span_pos(), - None, - ); - }; - } } /// Generate suggestions for keyword argument errors. diff --git a/kclvm/sema/src/resolver/attr.rs b/kclvm/sema/src/resolver/attr.rs index 6c8edf788..465b8c747 100644 --- a/kclvm/sema/src/resolver/attr.rs +++ b/kclvm/sema/src/resolver/attr.rs @@ -8,7 +8,7 @@ use crate::ty::{ DictType, ModuleKind, Parameter, Type, TypeKind, TypeRef, SCHEMA_MEMBER_FUNCTIONS, }; use kclvm_ast::ast; -use kclvm_error::diagnostic::Range; +use kclvm_error::diagnostic::{dummy_range, Range}; use kclvm_error::*; use super::node::ResolvedResult; @@ -80,6 +80,7 @@ impl<'ctx> Resolver<'ctx> { ty: Type::bool_ref(), // Default value is False has_default: true, + range: dummy_range(), }], "", false, diff --git a/kclvm/sema/src/resolver/global.rs b/kclvm/sema/src/resolver/global.rs index f103b65ce..238fff837 100644 --- a/kclvm/sema/src/resolver/global.rs +++ b/kclvm/sema/src/resolver/global.rs @@ -753,6 +753,7 @@ impl<'ctx> Resolver<'ctx> { name, ty: ty.clone(), has_default: args.node.defaults.get(i).map_or(false, |arg| arg.is_some()), + range: args.node.args[i].get_span_pos(), }); } } @@ -864,6 +865,7 @@ impl<'ctx> Resolver<'ctx> { name, ty: ty.clone(), has_default: args.node.defaults.get(i).is_some(), + range: args.node.args[i].get_span_pos(), }); } } diff --git a/kclvm/sema/src/resolver/node.rs b/kclvm/sema/src/resolver/node.rs index bd78ba69b..0150daaf6 100644 --- a/kclvm/sema/src/resolver/node.rs +++ b/kclvm/sema/src/resolver/node.rs @@ -184,12 +184,8 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { target.get_span_pos(), None, ); - - let upgrade_schema_type = self.upgrade_dict_to_schema( - value_ty.clone(), - expected_ty.clone(), - &assign_stmt.value.get_span_pos(), - ); + let upgrade_schema_type = + self.upgrade_dict_to_schema(value_ty.clone(), expected_ty.clone()); self.node_ty_map.borrow_mut().insert( self.get_node_key(assign_stmt.value.id.clone()), upgrade_schema_type.clone(), @@ -222,12 +218,8 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { target.get_span_pos(), None, ); - - let upgrade_schema_type = self.upgrade_dict_to_schema( - value_ty.clone(), - expected_ty.clone(), - &assign_stmt.value.get_span_pos(), - ); + let upgrade_schema_type = + self.upgrade_dict_to_schema(value_ty.clone(), expected_ty.clone()); self.node_ty_map.borrow_mut().insert( self.get_node_key(assign_stmt.value.id.clone()), upgrade_schema_type.clone(), @@ -992,6 +984,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { name, ty: ty.clone(), has_default: value.is_some(), + range: args.node.args[i].get_span_pos(), }); self.expr_or_any_type(value); } @@ -1031,27 +1024,41 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { ); } } - let real_ret_ty = self.stmts(&lambda_expr.body); - self.leave_scope(); - self.ctx.in_lambda_expr.pop(); - self.must_assignable_to(real_ret_ty.clone(), ret_ty.clone(), (start, end), None); - - // upgrade return value type to schema if return type is schema - if let Some(stmt) = lambda_expr.body.last() { + // Walk lambda body statements except the last statement. + if lambda_expr.body.len() > 1 { + self.stmts(&lambda_expr.body[..lambda_expr.body.len() - 1]); + } + // Upgrade return value type to schema if return type is schema + let real_ret_ty = if let Some(stmt) = lambda_expr.body.last() { if let ast::Stmt::Expr(expr_stmt) = &stmt.node { if let Some(expr) = expr_stmt.exprs.last() { - let upgrade_schema_type = self.upgrade_dict_to_schema( + self.upgrade_type_for_expr( + ret_ty.clone(), + expr, + expr.get_span_pos(), + lambda_expr.return_ty.as_ref().map(|ty| ty.get_span_pos()), + ) + } else { + let real_ret_ty = self.stmt(stmt); + self.must_assignable_to( real_ret_ty.clone(), ret_ty.clone(), - &stmt.get_span_pos(), - ); - self.node_ty_map.borrow_mut().insert( - self.get_node_key(expr.id.clone()), - upgrade_schema_type.clone(), + (start, end), + None, ); + real_ret_ty } + } else { + let real_ret_ty = self.stmt(stmt); + self.must_assignable_to(real_ret_ty.clone(), ret_ty.clone(), (start, end), None); + real_ret_ty } - } + } else { + self.any_ty() + }; + // Leave the lambda scope. + self.leave_scope(); + self.ctx.in_lambda_expr.pop(); if !real_ret_ty.is_any() && ret_ty.is_any() && lambda_expr.return_ty.is_none() { ret_ty = real_ret_ty; @@ -1245,8 +1252,7 @@ impl<'ctx> Resolver<'ctx> { let ty = self.walk_expr(&expr.node); if let Some(expected_ty) = expected_ty { - let upgrade_ty = - self.upgrade_dict_to_schema(ty.clone(), expected_ty, &expr.get_span_pos()); + let upgrade_ty = self.upgrade_dict_to_schema(ty.clone(), expected_ty); self.node_ty_map .borrow_mut() .insert(self.get_node_key(expr.id.clone()), upgrade_ty); diff --git a/kclvm/sema/src/resolver/schema.rs b/kclvm/sema/src/resolver/schema.rs index 4b42df4f7..05c3c8c13 100644 --- a/kclvm/sema/src/resolver/schema.rs +++ b/kclvm/sema/src/resolver/schema.rs @@ -4,11 +4,12 @@ use std::rc::Rc; use crate::builtin::BUILTIN_DECORATORS; use crate::resolver::Resolver; -use crate::ty::{Decorator, DecoratorTarget, TypeKind}; +use crate::ty::{Decorator, DecoratorTarget, TypeKind, TypeRef}; use kclvm_ast::ast; use kclvm_ast::pos::GetPos; use kclvm_ast::walker::MutSelfTypedResultWalker; use kclvm_ast_pretty::{print_ast_node, ASTNode}; +use kclvm_error::diagnostic::Range; use kclvm_error::{ErrorKind, Message, Position, Style}; use super::node::ResolvedResult; @@ -245,6 +246,42 @@ impl<'ctx> Resolver<'ctx> { decorator_objs } + /// Walk expr and check the type and return the value type. + pub(crate) fn upgrade_type_for_expr( + &mut self, + expected_ty: TypeRef, + expr: &'ctx ast::NodeRef, + target_range: Range, + def_range: Option, + ) -> TypeRef { + let (start, end) = expr.get_span_pos(); + let value_ty = match &expected_ty.kind { + TypeKind::Schema(ty) => { + let obj = + self.new_config_expr_context_item(&ty.name, expected_ty.clone(), start, end); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + let value_ty = self.expr(expr); + self.clear_config_expr_context(init_stack_depth as usize, false); + value_ty + } + TypeKind::List(_) | TypeKind::Dict(_) | TypeKind::Union(_) => { + let obj = self.new_config_expr_context_item("[]", expected_ty.clone(), start, end); + let init_stack_depth = self.switch_config_expr_context(Some(obj)); + let value_ty = self.expr(expr); + self.clear_config_expr_context(init_stack_depth as usize, false); + value_ty + } + _ => self.expr(expr), + }; + self.must_assignable_to( + value_ty.clone(), + expected_ty.clone(), + target_range, + def_range, + ); + value_ty + } + fn arguments_to_string( &mut self, args: &'ctx [ast::NodeRef], diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_0.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_0.k new file mode 100644 index 000000000..69d1097ec --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_0.k @@ -0,0 +1,11 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + {} +} + +v = providerFamily({ + version: 1 +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_1.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_1.k new file mode 100644 index 000000000..a1f350f7c --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_1.k @@ -0,0 +1,12 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + {} +} + +v = providerFamily({ + version: "1.6.0" + hello: "world" +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_2.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_2.k new file mode 100644 index 000000000..fbf135d45 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_2.k @@ -0,0 +1,13 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + version: 1 + } +} + +v = providerFamily({ + version: "1.6.0" +}) diff --git a/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_3.k b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_3.k new file mode 100644 index 000000000..65da2f660 --- /dev/null +++ b/kclvm/sema/src/resolver/test_fail_data/lambda_schema_ty_3.k @@ -0,0 +1,14 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + version: "1.6.0" + hello: "world" + } +} + +v = providerFamily({ + version: "1.6.0" +}) diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs index 811267ede..65985270b 100644 --- a/kclvm/sema/src/resolver/tests.rs +++ b/kclvm/sema/src/resolver/tests.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use std::sync::Mutex; pub fn parse_program(filename: &str) -> Result { - let abspath = std::fs::canonicalize(std::path::PathBuf::from(filename)).unwrap(); + let abspath = std::fs::canonicalize(std::path::PathBuf::from(filename)).expect(filename); let mut prog = ast::Program { root: abspath.parent().unwrap().adjust_canonicalization(), @@ -154,6 +154,10 @@ fn test_resolve_program_fail() { "comp_clause_error_4.k", "config_expr.k", "invalid_mixin_0.k", + "lambda_schema_ty_0.k", + "lambda_schema_ty_1.k", + "lambda_schema_ty_2.k", + "lambda_schema_ty_3.k", "module_optional_select.k", "mutable_error_0.k", "mutable_error_1.k", diff --git a/kclvm/sema/src/resolver/ty.rs b/kclvm/sema/src/resolver/ty.rs index e0d88a146..f37e38182 100644 --- a/kclvm/sema/src/resolver/ty.rs +++ b/kclvm/sema/src/resolver/ty.rs @@ -104,7 +104,7 @@ impl<'ctx> Resolver<'ctx> { ty: TypeRef, expected_ty: TypeRef, range: Range, - expected_pos: Option, + def_range: Option, ) { if !self.check_type(ty.clone(), expected_ty.clone(), &range) { let mut msgs = vec![Message { @@ -115,42 +115,41 @@ impl<'ctx> Resolver<'ctx> { suggested_replacement: None, }]; - if let Some(expected_pos) = expected_pos { - msgs.push(Message { - range: expected_pos, - style: Style::LineAndColumn, - message: format!( - "variable is defined here, its type is {}, but got {}", - expected_ty.ty_str(), - ty.ty_str(), - ), - note: None, - suggested_replacement: None, - }); + if let Some(def_range) = def_range { + // If the range is not a dummy range, append the definition error message + // in the diagnostic. + if !def_range.0.filename.is_empty() && !def_range.1.filename.is_empty() { + msgs.push(Message { + range: def_range, + style: Style::LineAndColumn, + message: format!( + "variable is defined here, its type is {}, but got {}", + expected_ty.ty_str(), + ty.ty_str(), + ), + note: None, + suggested_replacement: None, + }); + } } self.handler.add_error(ErrorKind::TypeError, &msgs); } } // Upgrade the dict type into schema type if it is expected to schema - pub fn upgrade_dict_to_schema( - &mut self, - ty: TypeRef, - expected_ty: TypeRef, - range: &Range, - ) -> TypeRef { + pub(crate) fn upgrade_dict_to_schema(&mut self, ty: TypeRef, expected_ty: TypeRef) -> TypeRef { match (&ty.kind, &expected_ty.kind) { - (TypeKind::Dict(DictType { key_ty, .. }), TypeKind::Schema(schema_ty)) => { - if self.upgrade_dict_to_schema_attr_check(key_ty.clone(), schema_ty) { + (TypeKind::Dict(dict_ty), TypeKind::Schema(schema_ty)) => { + if self.upgrade_dict_to_schema_attr_check(dict_ty, schema_ty) { expected_ty } else { ty } } - (TypeKind::List(item_ty), TypeKind::List(expected_item_ty)) => Type::list( - self.upgrade_dict_to_schema(item_ty.clone(), expected_item_ty.clone(), range), - ) - .into(), + (TypeKind::List(item_ty), TypeKind::List(expected_item_ty)) => { + Type::list(self.upgrade_dict_to_schema(item_ty.clone(), expected_item_ty.clone())) + .into() + } ( TypeKind::Dict(DictType { key_ty, val_ty, .. }), TypeKind::Dict(DictType { @@ -159,11 +158,11 @@ impl<'ctx> Resolver<'ctx> { .. }), ) => Type::dict( - self.upgrade_dict_to_schema(key_ty.clone(), expected_key_ty.clone(), range), - self.upgrade_dict_to_schema(val_ty.clone(), expected_val_ty.clone(), range), + self.upgrade_dict_to_schema(key_ty.clone(), expected_key_ty.clone()), + self.upgrade_dict_to_schema(val_ty.clone(), expected_val_ty.clone()), ) .into(), - (TypeKind::Dict(DictType { key_ty, .. }), TypeKind::Union(expected_union_type)) => { + (TypeKind::Dict(dict_ty), TypeKind::Union(expected_union_type)) => { let types: Vec> = expected_union_type .iter() .filter(|ty| match ty.kind { @@ -171,10 +170,7 @@ impl<'ctx> Resolver<'ctx> { _ => false, }) .filter(|ty| { - self.upgrade_dict_to_schema_attr_check( - key_ty.clone(), - &ty.into_schema_type(), - ) + self.upgrade_dict_to_schema_attr_check(dict_ty, &ty.into_schema_type()) }) .map(|ty| ty.clone()) .collect(); @@ -248,6 +244,7 @@ impl<'ctx> Resolver<'ctx> { /// The check type main function, returns a boolean result. #[inline] pub fn check_type(&mut self, ty: TypeRef, expected_ty: TypeRef, range: &Range) -> bool { + // Check assignable between types. match (&ty.kind, &expected_ty.kind) { (TypeKind::List(item_ty), TypeKind::List(expected_item_ty)) => { self.check_type(item_ty.clone(), expected_item_ty.clone(), range) @@ -263,8 +260,8 @@ impl<'ctx> Resolver<'ctx> { self.check_type(key_ty.clone(), expected_key_ty.clone(), range) && self.check_type(val_ty.clone(), expected_val_ty.clone(), range) } - (TypeKind::Dict(DictType { key_ty, val_ty, .. }), TypeKind::Schema(schema_ty)) => { - self.dict_assignable_to_schema(key_ty.clone(), val_ty.clone(), schema_ty, range) + (TypeKind::Dict(dict_ty), TypeKind::Schema(schema_ty)) => { + self.dict_assignable_to_schema(dict_ty, schema_ty, range) } (TypeKind::Union(types), _) => types .iter() @@ -278,13 +275,13 @@ impl<'ctx> Resolver<'ctx> { /// Judge a dict can be converted to schema in compile time /// Do relaxed schema check key and value type check. - pub fn dict_assignable_to_schema( + pub(crate) fn dict_assignable_to_schema( &mut self, - key_ty: TypeRef, - val_ty: TypeRef, + dict_ty: &DictType, schema_ty: &SchemaType, range: &Range, ) -> bool { + let (key_ty, val_ty) = (dict_ty.key_ty.clone(), dict_ty.val_ty.clone()); if let Some(index_signature) = &schema_ty.index_signature { let val_ty = match (&key_ty.kind, &val_ty.kind) { (TypeKind::Union(key_tys), TypeKind::Union(val_tys)) => { @@ -339,13 +336,13 @@ impl<'ctx> Resolver<'ctx> { /// More strict than `dict_assign_to_schema()`: schema attr contains all attributes in key pub fn upgrade_dict_to_schema_attr_check( &mut self, - key_ty: TypeRef, + dict_ty: &DictType, schema_ty: &SchemaType, ) -> bool { if schema_ty.index_signature.is_some() { return true; } - match &key_ty.kind { + match &dict_ty.key_ty.kind { // empty dict {} TypeKind::Any => true, // single key: {key1: value1} @@ -362,7 +359,7 @@ impl<'ctx> Resolver<'ctx> { TypeKind::StrLit(s) => attrs.contains(s), _ => false, }), - // Todo: do more index_signature check + // TODO: do more index_signature check with dict type attrs (false, true) => true, (false, false) => false, } @@ -508,6 +505,7 @@ impl<'ctx> Resolver<'ctx> { Some(ast_ty.as_ref()), ), has_default: ty.has_default, + range: ty_node.get_span_pos(), }); } } diff --git a/kclvm/sema/src/ty/into.rs b/kclvm/sema/src/ty/into.rs index f73fb9327..f08fb49d9 100644 --- a/kclvm/sema/src/ty/into.rs +++ b/kclvm/sema/src/ty/into.rs @@ -1,4 +1,5 @@ use super::*; +use kclvm_ast::pos::GetPos; impl Type { /// Downcast ty into the list type. @@ -185,6 +186,7 @@ impl From for Type { name: "".to_string(), ty: Arc::new(ty.node.clone().into()), has_default: false, + range: ty.get_span_pos(), }) .collect::>() }) diff --git a/kclvm/sema/src/ty/mod.rs b/kclvm/sema/src/ty/mod.rs index 2910beb1e..d4b4e34b8 100644 --- a/kclvm/sema/src/ty/mod.rs +++ b/kclvm/sema/src/ty/mod.rs @@ -497,10 +497,11 @@ impl FunctionType { } } -/// The function parameter. +/// The function parameter type and position information. #[derive(Debug, Clone, PartialEq)] pub struct Parameter { pub name: String, pub ty: TypeRef, pub has_default: bool, + pub range: Range, } diff --git a/kclvm/tools/src/LSP/src/to_lsp.rs b/kclvm/tools/src/LSP/src/to_lsp.rs index 2110ab1b7..3b1150015 100644 --- a/kclvm/tools/src/LSP/src/to_lsp.rs +++ b/kclvm/tools/src/LSP/src/to_lsp.rs @@ -69,16 +69,20 @@ fn kcl_msg_to_lsp_diags( Some( related_msg .iter() - .map(|m| DiagnosticRelatedInformation { - location: Location { - uri: Url::from_file_path(m.range.0.filename.clone()).unwrap(), - range: Range { - start: lsp_pos(&m.range.0), - end: lsp_pos(&m.range.1), + .map(|m| match Url::from_file_path(m.range.0.filename.clone()) { + Ok(uri) => Some(DiagnosticRelatedInformation { + location: Location { + uri, + range: Range { + start: lsp_pos(&m.range.0), + end: lsp_pos(&m.range.1), + }, }, - }, - message: m.message.clone(), + message: m.message.clone(), + }), + Err(_) => None, }) + .flatten() .collect(), ) }; diff --git a/test/grammar/lambda/type_annotation/schema/invalid_0/main.k b/test/grammar/lambda/type_annotation/schema/invalid_0/main.k new file mode 100644 index 000000000..e1d07ec55 --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_0/main.k @@ -0,0 +1,16 @@ +schema ProviderFamily: + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + **family + version: 1 + hello: "world" + } +} + +v = providerFamily({ + version: 1 + hello: "world" +}) diff --git a/test/grammar/lambda/type_annotation/schema/invalid_0/stderr.golden b/test/grammar/lambda/type_annotation/schema/invalid_0/stderr.golden new file mode 100644 index 000000000..9224a44f0 --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_0/stderr.golden @@ -0,0 +1,39 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:8:9 + | +8 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:2:5 + | +2 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:9:9 + | +9 | hello: "world" + | ^ Cannot add member 'hello' to schema 'ProviderFamily' + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:14:5 + | +14 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:2:5 + | +2 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2L23]: CompileError + --> ${CWD}/main.k:15:5 + | +15 | hello: "world" + | ^ Cannot add member 'hello' to schema 'ProviderFamily' + | \ No newline at end of file diff --git a/test/grammar/lambda/type_annotation/schema/invalid_1/main.k b/test/grammar/lambda/type_annotation/schema/invalid_1/main.k new file mode 100644 index 000000000..b7463726d --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_1/main.k @@ -0,0 +1,17 @@ +schema ProviderFamily: + [...str]: int + version: str + marketplace: bool = True + +providerFamily = lambda family: ProviderFamily -> ProviderFamily { + { + **family + version: 1 + hello: "world" + } +} + +v = providerFamily({ + version: 1 + hello: "world" +}) diff --git a/test/grammar/lambda/type_annotation/schema/invalid_1/stderr.golden b/test/grammar/lambda/type_annotation/schema/invalid_1/stderr.golden new file mode 100644 index 000000000..800a02d77 --- /dev/null +++ b/test/grammar/lambda/type_annotation/schema/invalid_1/stderr.golden @@ -0,0 +1,71 @@ +error[E2G22]: TypeError + --> ${CWD}/main.k:9:9 + | +9 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:3:5 + | +3 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:10:9 + | +10 | hello: "world" + | ^ expected int, got str(world) + | + + --> ${CWD}/main.k:7:5 + | +7 | { + | ^ variable is defined here, its type is int, but got str(world) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:15:5 + | +15 | version: 1 + | ^ expected str, got int(1) + | + + --> ${CWD}/main.k:3:5 + | +3 | version: str + | ^ variable is defined here, its type is str, but got int(1) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:16:5 + | +16 | hello: "world" + | ^ expected int, got str(world) + | + + --> ${CWD}/main.k:14:20 + | +14 | v = providerFamily({ + | ^ variable is defined here, its type is int, but got str(world) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:14:20 + | +14 | v = providerFamily({ + | ^ expected schema index signature value type int, got str(world) + | + +error[E2G22]: TypeError + --> ${CWD}/main.k:14:20 + | +14 | v = providerFamily({ + | ^ expected ProviderFamily, got {str(version) | str(hello):int(1) | str(world)} + | + + --> ${CWD}/main.k:6:25 + | +6 | providerFamily = lambda family: ProviderFamily -> ProviderFamily { + | ^ variable is defined here, its type is ProviderFamily, but got {str(version) | str(hello):int(1) | str(world)} + | diff --git a/test/grammar/schema/index_signature/fail_1/stderr.golden b/test/grammar/schema/index_signature/fail_1/stderr.golden index 5204bfea8..5616cf817 100644 --- a/test/grammar/schema/index_signature/fail_1/stderr.golden +++ b/test/grammar/schema/index_signature/fail_1/stderr.golden @@ -10,4 +10,3 @@ error[E2G22]: TypeError 6 | name: "test" | ^ expected int, got str(test) | -variable is defined here, its type is int, but got str(test) \ No newline at end of file diff --git a/test/grammar/schema/index_signature/fail_3/stderr.golden b/test/grammar/schema/index_signature/fail_3/stderr.golden index bb32e668e..62193a25c 100644 --- a/test/grammar/schema/index_signature/fail_3/stderr.golden +++ b/test/grammar/schema/index_signature/fail_3/stderr.golden @@ -4,4 +4,3 @@ error[E2G22]: TypeError 5 | name: "test" | ^ expected int, got str(test) | -variable is defined here, its type is int, but got str(test) \ No newline at end of file diff --git a/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden b/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden index fac3bbf6f..6d7426043 100644 --- a/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden +++ b/test/grammar/schema/init/init_kwargs_fail_0/stderr.golden @@ -1,12 +1,13 @@ error[E2L23]: CompileError - --> ${CWD}/main.k:4:10 + --> ${CWD}/main.k:4:17 | 4 | person = Person(_naem="Alice") {} - | ^ expected 1 positional argument, found 0 + | ^ "Person" got an unexpected keyword argument '_naem', did you mean '_name'? | + error[E2L23]: CompileError - --> ${CWD}/main.k:4:17 + --> ${CWD}/main.k:4:10 | 4 | person = Person(_naem="Alice") {} - | ^ "Person" got an unexpected keyword argument '_naem', did you mean '_name'? - | \ No newline at end of file + | ^ expected 1 positional argument, found 0 + | diff --git a/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden b/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden index 242812d0a..9b9b231d8 100644 --- a/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden +++ b/test/grammar/schema/type_annotation/type_annotation_inconsistent/stderr.golden @@ -4,9 +4,16 @@ error[E2G22]: TypeError 4 | c: str = a3 | ^ expected str, got int | + error[E2G22]: TypeError - --> ${CWD}/main.k:7:17 + --> ${CWD}/main.k:7:20 | 7 | a = A(a1=1,a2=2,a3="3") - | ^ expected int, got str(3) - | \ No newline at end of file + | ^ expected int, got str(3) + | + + --> ${CWD}/main.k:1:23 + | +1 | schema A[a1, a2: int, a3: int]: + | ^ variable is defined here, its type is int, but got str(3) + | diff --git a/test/grammar/types/args/lambda_types_err_02/stderr.golden b/test/grammar/types/args/lambda_types_err_02/stderr.golden index df2d031c3..c0ac0d234 100644 --- a/test/grammar/types/args/lambda_types_err_02/stderr.golden +++ b/test/grammar/types/args/lambda_types_err_02/stderr.golden @@ -4,9 +4,22 @@ error[E2G22]: TypeError 6 | x1 = typeFunc("1", "Golang") | ^ expected int, got str(1) | + + --> ${CWD}/main.k:1:19 + | +1 | typeFunc = lambda age_: int, name_: "KCL"|"CUE" { + | ^ variable is defined here, its type is int, but got str(1) + | + error[E2G22]: TypeError --> ${CWD}/main.k:6:20 | 6 | x1 = typeFunc("1", "Golang") | ^ expected str(KCL) | str(CUE), got str(Golang) - | \ No newline at end of file + | + + --> ${CWD}/main.k:1:30 + | +1 | typeFunc = lambda age_: int, name_: "KCL"|"CUE" { + | ^ variable is defined here, its type is str(KCL) | str(CUE), but got str(Golang) + | diff --git a/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden b/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden index 0d5874669..5c383980f 100644 --- a/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden +++ b/test/grammar/types/args/schema_types_err_05_kwargs/stderr.golden @@ -1,6 +1,12 @@ error[E2G22]: TypeError - --> ${CWD}/main.k:5:31 + --> ${CWD}/main.k:5:33 | 5 | person = Person(data="Alice", n="1") - | ^ expected int, got str(1) - | \ No newline at end of file + | ^ expected int, got str(1) + | + + --> ${CWD}/main.k:1:26 + | +1 | schema Person[data: str, n: int]: + | ^ variable is defined here, its type is int, but got str(1) + |