diff --git a/src/cli/lib.rs b/src/cli/lib.rs index 182c6e7e..ef32cdf2 100644 --- a/src/cli/lib.rs +++ b/src/cli/lib.rs @@ -9,7 +9,7 @@ use hakana_reflection_info::Interner; use indexmap::IndexMap; use rand::Rng; use rustc_hash::FxHashSet; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::env; use std::fs::{self, File}; use std::io::Write; @@ -1056,15 +1056,17 @@ fn do_codegen( errors.push(format!("File {} doesn’t exist", name)); continue; } - } else if check_codegen || !overwrite_codegen { + } else { let existing_contents = fs::read_to_string(path).unwrap(); if existing_contents.trim() != info.trim() { - errors.push(format!("File {} differs from codegen", name,)); + if check_codegen || !overwrite_codegen { + errors.push(format!("File {} differs from codegen", name)); + continue; + } } else { verified_count += 1; + continue; } - - continue; } if let Some(dir) = path.parent() { @@ -1072,6 +1074,7 @@ fn do_codegen( } let mut output_path = fs::File::create(path).unwrap(); write!(output_path, "{}", &info).unwrap(); + println!("Saved {}", name); updated_count += 1; } diff --git a/src/code_info/t_atomic.rs b/src/code_info/t_atomic.rs index e6e45b78..2e5ba0ff 100644 --- a/src/code_info/t_atomic.rs +++ b/src/code_info/t_atomic.rs @@ -161,24 +161,33 @@ pub enum TAtomic { impl TAtomic { pub fn get_id(&self, interner: Option<&Interner>) -> String { - self.get_id_with_refs(interner, &mut vec![]) + self.get_id_with_refs(interner, &mut vec![], None) } - pub fn get_id_with_refs(&self, interner: Option<&Interner>, refs: &mut Vec) -> String { + pub fn get_id_with_refs( + &self, + interner: Option<&Interner>, + refs: &mut Vec, + indent: Option, + ) -> String { match self { TAtomic::TArraykey { .. } => "arraykey".to_string(), TAtomic::TBool { .. } => "bool".to_string(), TAtomic::TClassname { as_type, .. } => { let mut str = String::new(); str += "classname<"; - str += as_type.get_id_with_refs(interner, &mut vec![]).as_str(); + str += as_type + .get_id_with_refs(interner, &mut vec![], indent) + .as_str(); str += ">"; str } TAtomic::TTypename { as_type, .. } => { let mut str = String::new(); str += "typename<"; - str += as_type.get_id_with_refs(interner, &mut vec![]).as_str(); + str += as_type + .get_id_with_refs(interner, &mut vec![], indent) + .as_str(); str += ">"; str } @@ -215,6 +224,11 @@ impl TAtomic { if let Some(known_items) = known_items { str += "shape("; + if let Some(indent) = indent { + str += "\n"; + str += &("\t".repeat(indent + 1)); + } + str += known_items .iter() .map(|(property, (u, property_type))| { @@ -222,29 +236,52 @@ impl TAtomic { "{}{} => {}", if *u { "?" } else { "" }, property.to_string(interner), - property_type.get_id_with_refs(interner, refs) + property_type.get_id_with_refs( + interner, + refs, + if let Some(indent) = indent { + Some(indent + 1) + } else { + None + } + ) ) }) - .join(", ") + .join(&if let Some(indent) = indent { + format!("\n{}", "\t".repeat(indent + 1)) + } else { + ", ".to_string() + }) .as_str(); if let Some(params) = params { - str += ", ...dict<"; - str += params.0.get_id_with_refs(interner, refs).as_str(); - str += ","; - str += params.1.get_id_with_refs(interner, refs).as_str(); + if let Some(indent) = indent { + str += &format!("\n{}", "\t".repeat(indent + 1)); + } else { + str += ", " + } + + str += "...dict<"; + str += params.0.get_id_with_refs(interner, refs, indent).as_str(); + str += ", "; + str += params.1.get_id_with_refs(interner, refs, indent).as_str(); str += ">"; } + if let Some(indent) = indent { + str += "\n"; + str += &("\t".repeat(indent)); + } + str += ")"; return str; } if let Some(params) = params { str += "dict<"; - str += params.0.get_id_with_refs(interner, refs).as_str(); - str += ","; - str += params.1.get_id_with_refs(interner, refs).as_str(); + str += params.0.get_id_with_refs(interner, refs, indent).as_str(); + str += ", "; + str += params.1.get_id_with_refs(interner, refs, indent).as_str(); str += ">"; str } else { @@ -275,7 +312,7 @@ impl TAtomic { format!( "{}{}", if let Some(param_type) = ¶m.signature_type { - param_type.get_id_with_refs(interner, refs) + param_type.get_id_with_refs(interner, refs, indent) } else { "mixed".to_string() }, @@ -287,7 +324,9 @@ impl TAtomic { str += "): "; if let Some(return_type) = return_type { - str += return_type.get_id_with_refs(interner, refs).as_str(); + str += return_type + .get_id_with_refs(interner, refs, indent) + .as_str(); } else { str += "mixed"; } @@ -311,7 +350,7 @@ impl TAtomic { TAtomic::TKeyset { type_param, .. } => { let mut str = String::new(); str += "keyset<"; - str += type_param.get_id_with_refs(interner, refs).as_str(); + str += type_param.get_id_with_refs(interner, refs, indent).as_str(); str += ">"; str } @@ -403,7 +442,7 @@ impl TAtomic { "&".to_string() + extra_types .iter() - .map(|atomic| atomic.get_id_with_refs(interner, refs)) + .map(|atomic| atomic.get_id_with_refs(interner, refs, indent)) .join("&") .as_str() } else { @@ -423,7 +462,7 @@ impl TAtomic { str += "<"; str += type_params .iter() - .map(|tunion| tunion.get_id_with_refs(interner, refs)) + .map(|tunion| tunion.get_id_with_refs(interner, refs, indent)) .join(", ") .as_str(); str += ">"; @@ -457,7 +496,7 @@ impl TAtomic { str += "<"; str += type_params .iter() - .map(|tunion| tunion.get_id_with_refs(interner, refs)) + .map(|tunion| tunion.get_id_with_refs(interner, refs, indent)) .join(", ") .as_str(); str += ">)"; @@ -558,13 +597,13 @@ impl TAtomic { str += "tuple("; str += known_items .iter() - .map(|(_, (_, tunion))| tunion.get_id_with_refs(interner, refs)) + .map(|(_, (_, tunion))| tunion.get_id_with_refs(interner, refs, indent)) .join(", ") .as_str(); if !type_param.is_nothing() { str += ", ...vec<"; - str += type_param.get_id_with_refs(interner, refs).as_str(); + str += type_param.get_id_with_refs(interner, refs, indent).as_str(); str += ">"; } @@ -573,7 +612,7 @@ impl TAtomic { } let mut str = String::new(); str += if *non_empty { "non-empty-vec<" } else { "vec<" }; - str += type_param.get_id_with_refs(interner, refs).as_str(); + str += type_param.get_id_with_refs(interner, refs, indent).as_str(); str += ">"; str } @@ -597,7 +636,7 @@ impl TAtomic { } => { format!( "{}::{}", - class_type.get_id_with_refs(interner, refs), + class_type.get_id_with_refs(interner, refs, indent), if let Some(interner) = interner { interner.lookup(member_name).to_string() } else { @@ -676,7 +715,7 @@ impl TAtomic { | TAtomic::TBool { .. } | TAtomic::TEnumClassLabel { .. } | TAtomic::TMixedWithFlags(..) - | TAtomic::TTypeVariable { .. } => self.get_id_with_refs(None, &mut vec![]), + | TAtomic::TTypeVariable { .. } => self.get_id_with_refs(None, &mut vec![], None), TAtomic::TStringWithFlags(..) => "string".to_string(), diff --git a/src/code_info/t_union.rs b/src/code_info/t_union.rs index 86f16098..e1810d4f 100644 --- a/src/code_info/t_union.rs +++ b/src/code_info/t_union.rs @@ -488,15 +488,35 @@ impl TUnion { } pub fn get_id(&self, interner: Option<&Interner>) -> String { - self.get_id_with_refs(interner, &mut vec![]) - } - - pub fn get_id_with_refs(&self, interner: Option<&Interner>, refs: &mut Vec) -> String { - let mut tatomic_strings = self - .types - .iter() - .map(|atomic| atomic.get_id_with_refs(interner, refs)); - tatomic_strings.join("|") + self.get_id_with_refs(interner, &mut vec![], None) + } + + pub fn get_id_with_refs( + &self, + interner: Option<&Interner>, + refs: &mut Vec, + indent: Option, + ) -> String { + if self.types.len() == 2 { + match (&self.types[0], &self.types[1]) { + (TAtomic::TNull, a) | (a, TAtomic::TNull) => { + format!("?{}", a.get_id_with_refs(interner, refs, indent)) + } + (a, b) => { + format!( + "{}|{}", + a.get_id_with_refs(interner, refs, indent), + b.get_id_with_refs(interner, refs, indent) + ) + } + } + } else { + let mut tatomic_strings = self + .types + .iter() + .map(|atomic| atomic.get_id_with_refs(interner, refs, indent)); + tatomic_strings.join("|") + } } #[inline] diff --git a/tests/diff/classConstTypeChanged/output.txt b/tests/diff/classConstTypeChanged/output.txt index c8a06373..9b4a7d50 100644 --- a/tests/diff/classConstTypeChanged/output.txt +++ b/tests/diff/classConstTypeChanged/output.txt @@ -1 +1 @@ -ERROR: InvalidArgument - input.hack:13:14 - Argument 1 of echo expects scalar|null, different type Exception provided \ No newline at end of file +ERROR: InvalidArgument - input.hack:13:14 - Argument 1 of echo expects ?scalar, different type Exception provided \ No newline at end of file diff --git a/tests/diff/commentOutClassInOtherFile/output.txt b/tests/diff/commentOutClassInOtherFile/output.txt index 66040115..bc7ecf4a 100644 --- a/tests/diff/commentOutClassInOtherFile/output.txt +++ b/tests/diff/commentOutClassInOtherFile/output.txt @@ -1,7 +1,7 @@ ERROR: NonExistentClass - input.hack:8:11 - Cannot call new on undefined class A ERROR: NonExistentType - input.hack:12:10 - Unknown class A -ERROR: MixedAnyArgument - input.hack:12:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:12:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentType - input.hack:17:14 - Unknown class A -ERROR: MixedAnyArgument - input.hack:17:14 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:17:14 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentClass - input.hack:21:15 - Cannot call new on undefined class A ERROR: InvalidReturnStatement - input.hack:26:16 - The type string(a) does not match the declared return type int for B::bat \ No newline at end of file diff --git a/tests/inference/ArrayAccess/mixedArrayAccessDictWrapped/output.txt b/tests/inference/ArrayAccess/mixedArrayAccessDictWrapped/output.txt index b277897e..8682acdf 100644 --- a/tests/inference/ArrayAccess/mixedArrayAccessDictWrapped/output.txt +++ b/tests/inference/ArrayAccess/mixedArrayAccessDictWrapped/output.txt @@ -1,2 +1,2 @@ -ERROR: PossiblyUndefinedStringArrayOffset - input.hack:6:10 - Fetch on dict using possibly-undefined key 'foo' -ERROR: MixedAnyArgument - input.hack:6:10 - Argument 1 of echo expects scalar|null, any provided \ No newline at end of file +ERROR: PossiblyUndefinedStringArrayOffset - input.hack:6:10 - Fetch on dict using possibly-undefined key 'foo' +ERROR: MixedAnyArgument - input.hack:6:10 - Argument 1 of echo expects ?scalar, any provided \ No newline at end of file diff --git a/tests/inference/ArrayAssignment/nestedKeysetAddition/output.txt b/tests/inference/ArrayAssignment/nestedKeysetAddition/output.txt index ef78f0f0..bfe5303f 100644 --- a/tests/inference/ArrayAssignment/nestedKeysetAddition/output.txt +++ b/tests/inference/ArrayAssignment/nestedKeysetAddition/output.txt @@ -1 +1 @@ -InvalidReturnStatement - input.hack:9:12 - The type dict> does not match the declared return type dict> for foo \ No newline at end of file +InvalidReturnStatement - input.hack:9:12 - The type dict> does not match the declared return type dict> for foo \ No newline at end of file diff --git a/tests/inference/ArrayFunctionCall/arrayContains/checksKeyIfArrayTypeMatch/output.txt b/tests/inference/ArrayFunctionCall/arrayContains/checksKeyIfArrayTypeMatch/output.txt index 0f293503..34219e8a 100644 --- a/tests/inference/ArrayFunctionCall/arrayContains/checksKeyIfArrayTypeMatch/output.txt +++ b/tests/inference/ArrayFunctionCall/arrayContains/checksKeyIfArrayTypeMatch/output.txt @@ -1,4 +1,4 @@ ERROR: ImpossibleKeyCheck - input.hack:7:9 - Type vec never has key 's' ERROR: ImpossibleKeyCheck - input.hack:11:9 - Type vec never has key 't' -ERROR: ImpossibleKeyCheck - input.hack:24:9 - Type dict never has key 1 -ERROR: ImpossibleKeyCheck - input.hack:28:9 - Type dict never has key 2 \ No newline at end of file +ERROR: ImpossibleKeyCheck - input.hack:24:9 - Type dict never has key 1 +ERROR: ImpossibleKeyCheck - input.hack:28:9 - Type dict never has key 2 \ No newline at end of file diff --git a/tests/inference/DictVecKeyset/dictFromKeys/output.txt b/tests/inference/DictVecKeyset/dictFromKeys/output.txt index c80c613f..dc1eceef 100644 --- a/tests/inference/DictVecKeyset/dictFromKeys/output.txt +++ b/tests/inference/DictVecKeyset/dictFromKeys/output.txt @@ -1,3 +1,3 @@ -ERROR: LessSpecificNestedAnyReturnStatement - input.hack:2:12 - The type dict is more general than the declared return type dict for foo +ERROR: LessSpecificNestedAnyReturnStatement - input.hack:2:12 - The type dict is more general than the declared return type dict for foo ERROR: MixedArgument - input.hack:3:9 - Argument 1 of HH\Lib\Dict\from_keys expects HH\Traversable, mixed provided ERROR: LessSpecificNestedAnyArgumentType - input.hack:4:28 - Argument 1 of takesString expects string, parent type arraykey provided \ No newline at end of file diff --git a/tests/inference/DictVecKeyset/lessSpecificTypeFromDictMixed/output.txt b/tests/inference/DictVecKeyset/lessSpecificTypeFromDictMixed/output.txt index 1b67afdf..8e77e3ea 100644 --- a/tests/inference/DictVecKeyset/lessSpecificTypeFromDictMixed/output.txt +++ b/tests/inference/DictVecKeyset/lessSpecificTypeFromDictMixed/output.txt @@ -1,4 +1,4 @@ -ERROR: LessSpecificNestedAnyArgumentType - input.hack:6:14 - Argument 1 of foo1 expects shape('id' => string, 'name' => string), parent type dict provided -ERROR: LessSpecificNestedAnyArgumentType - input.hack:7:14 - Argument 1 of foo2 expects shape('id' => string, 'name' => string, ...dict), parent type dict provided -ERROR: LessSpecificNestedArgumentType - input.hack:12:10 - Argument 1 of foo1 expects shape('id' => string, 'name' => string), parent type dict provided -ERROR: LessSpecificNestedArgumentType - input.hack:13:10 - Argument 1 of foo2 expects shape('id' => string, 'name' => string, ...dict), parent type dict provided \ No newline at end of file +ERROR: LessSpecificNestedAnyArgumentType - input.hack:6:14 - Argument 1 of foo1 expects shape('id' => string, 'name' => string), parent type dict provided +ERROR: LessSpecificNestedAnyArgumentType - input.hack:7:14 - Argument 1 of foo2 expects shape('id' => string, 'name' => string, ...dict), parent type dict provided +ERROR: LessSpecificNestedArgumentType - input.hack:12:10 - Argument 1 of foo1 expects shape('id' => string, 'name' => string), parent type dict provided +ERROR: LessSpecificNestedArgumentType - input.hack:13:10 - Argument 1 of foo2 expects shape('id' => string, 'name' => string, ...dict), parent type dict provided \ No newline at end of file diff --git a/tests/inference/DictVecKeyset/vecAnyIntoTypedVec/output.txt b/tests/inference/DictVecKeyset/vecAnyIntoTypedVec/output.txt index 74302686..14145c8d 100644 --- a/tests/inference/DictVecKeyset/vecAnyIntoTypedVec/output.txt +++ b/tests/inference/DictVecKeyset/vecAnyIntoTypedVec/output.txt @@ -1,2 +1,2 @@ ERROR: MixedAnyArgument - input.hack:4:29 - Argument 1 of HH\vec expects HH\Traversable, any provided -ERROR: LessSpecificNestedAnyArgumentType - input.hack:6:9 - Argument 1 of foo expects shape('a' => null|vec string)>), parent type shape('a' => vec|null) provided \ No newline at end of file +ERROR: LessSpecificNestedAnyArgumentType - input.hack:6:9 - Argument 1 of foo expects shape('a' => ?vec string)>), parent type shape('a' => ?vec) provided \ No newline at end of file diff --git a/tests/inference/Interface/interfaceRequireExtendsClassNegation/output.txt b/tests/inference/Interface/interfaceRequireExtendsClassNegation/output.txt index 24733963..15ba01c4 100644 --- a/tests/inference/Interface/interfaceRequireExtendsClassNegation/output.txt +++ b/tests/inference/Interface/interfaceRequireExtendsClassNegation/output.txt @@ -1 +1 @@ -ERROR: InvalidArgument - input.hack:21:10 - Argument 1 of echo expects scalar|null, different type Node provided \ No newline at end of file +ERROR: InvalidArgument - input.hack:21:10 - Argument 1 of echo expects ?scalar, different type Node provided \ No newline at end of file diff --git a/tests/inference/TypeAlias/classConstTypeAlias/output.txt b/tests/inference/TypeAlias/classConstTypeAlias/output.txt index aefd98c6..7fba5c40 100644 --- a/tests/inference/TypeAlias/classConstTypeAlias/output.txt +++ b/tests/inference/TypeAlias/classConstTypeAlias/output.txt @@ -1 +1 @@ -ERROR: InvalidArgument - input.hack:11:14 - Argument 1 of echo expects scalar|null, different type Exception provided \ No newline at end of file +ERROR: InvalidArgument - input.hack:11:14 - Argument 1 of echo expects ?scalar, different type Exception provided \ No newline at end of file diff --git a/tests/inference/TypeAlias/classConstTypeAliasViaTrait/output.txt b/tests/inference/TypeAlias/classConstTypeAliasViaTrait/output.txt index cc3c2864..9562cf77 100644 --- a/tests/inference/TypeAlias/classConstTypeAliasViaTrait/output.txt +++ b/tests/inference/TypeAlias/classConstTypeAliasViaTrait/output.txt @@ -1 +1 @@ -ERROR: InvalidArgument - input.hack:23:14 - Argument 1 of echo expects scalar|null, different type Exception provided \ No newline at end of file +ERROR: InvalidArgument - input.hack:23:14 - Argument 1 of echo expects ?scalar, different type Exception provided \ No newline at end of file diff --git a/tests/inference/TypeReconciliation/AsExpression/nestedAnyArrayAccess/output.txt b/tests/inference/TypeReconciliation/AsExpression/nestedAnyArrayAccess/output.txt index 41907c9d..be849fbf 100644 --- a/tests/inference/TypeReconciliation/AsExpression/nestedAnyArrayAccess/output.txt +++ b/tests/inference/TypeReconciliation/AsExpression/nestedAnyArrayAccess/output.txt @@ -1,4 +1,4 @@ ERROR: MixedAnyArrayAccess - input.hack:3:10 - Unsafe array access on value with type any ERROR: MixedAnyArrayAccess - input.hack:4:10 - Unsafe array access on value with type nonnull-from-any -ERROR: MixedAnyArgument - input.hack:4:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:4:10 - Argument 1 of echo expects ?scalar, any provided ERROR: MixedAnyReturnStatement - input.hack:5:12 - Could not infer a proper return type — saw nonnull-from-any \ No newline at end of file diff --git a/tests/nopanic/noclass/output.txt b/tests/nopanic/noclass/output.txt index b3e72fbe..2dfdb72f 100644 --- a/tests/nopanic/noclass/output.txt +++ b/tests/nopanic/noclass/output.txt @@ -1,15 +1,15 @@ ERROR: NonExistentClass - input.hack:2:12 - Cannot call new on undefined class Foo ERROR: MixedAnyReturnStatement - input.hack:2:12 - Could not infer a proper return type — saw any ERROR: NonExistentClasslike - input.hack:6:10 - Unknown classlike Foo -ERROR: MixedAnyArgument - input.hack:6:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:6:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentClasslike - input.hack:9:12 - Class, enum or interface Foo cannot be found ERROR: NonExistentClasslike - input.hack:13:10 - Unknown classlike Foo -ERROR: MixedAnyArgument - input.hack:13:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:13:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentClasslike - input.hack:23:5 - Unknown classlike Foo ERROR: NonExistentClass - input.hack:28:10 - Cannot access property on undefined class Foo -ERROR: MixedAnyArgument - input.hack:28:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:28:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentClass - input.hack:33:10 - Cannot access property on undefined class Foo -ERROR: InvalidArgument - input.hack:33:10 - Argument 1 of echo expects scalar|null, different type unknown-ref(Foo) provided +ERROR: InvalidArgument - input.hack:33:10 - Argument 1 of echo expects ?scalar, different type unknown-ref(Foo) provided ERROR: NonExistentClass - input.hack:37:10 - Cannot access property on undefined class Foo -ERROR: MixedAnyArgument - input.hack:37:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:37:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentClass - input.hack:42:9 - Undefined class Foo diff --git a/tests/nopanic/noclasslikemember/output.txt b/tests/nopanic/noclasslikemember/output.txt index ca833f35..f3e31d18 100644 --- a/tests/nopanic/noclasslikemember/output.txt +++ b/tests/nopanic/noclasslikemember/output.txt @@ -1,13 +1,13 @@ ERROR: NonExistentClassConstant - input.hack:8:10 - Unknown class constant Foo::B1 -ERROR: MixedAnyArgument - input.hack:8:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:8:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentClassConstant - input.hack:16:5 - Unknown class constant Foo::B3 ERROR: NonExistentClassConstant - input.hack:20:10 - Unknown class constant Foo::B4 -ERROR: MixedAnyArgument - input.hack:20:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:20:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentMethod - input.hack:24:5 - Method Foo::b5 does not exist ERROR: NonExistentMethod - input.hack:28:5 - Method Foo::b6 does not exist ERROR: NonExistentProperty - input.hack:32:10 - Cannot access undefined property Foo::$b7 -ERROR: MixedAnyArgument - input.hack:32:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:32:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentProperty - input.hack:36:10 - Cannot access undefined property Foo::$b8 -ERROR: InvalidArgument - input.hack:36:10 - Argument 1 of echo expects scalar|null, different type Foo provided +ERROR: InvalidArgument - input.hack:36:10 - Argument 1 of echo expects ?scalar, different type Foo provided ERROR: NonExistentProperty - input.hack:40:10 - Property Foo::$b9 is undefined ERROR: NonExistentProperty - input.hack:44:9 - Undefined property Foo::$b10 diff --git a/tests/nopanic/nofunction/output.txt b/tests/nopanic/nofunction/output.txt index ccfbb858..41277030 100644 --- a/tests/nopanic/nofunction/output.txt +++ b/tests/nopanic/nofunction/output.txt @@ -1,4 +1,4 @@ ERROR: NonExistentFunction - input.hack:2:5 - Function f1 is not defined ERROR: NonExistentFunction - input.hack:6:10 - Unknown function f2 -ERROR: MixedAnyArgument - input.hack:6:10 - Argument 1 of echo expects scalar|null, any provided +ERROR: MixedAnyArgument - input.hack:6:10 - Argument 1 of echo expects ?scalar, any provided ERROR: NonExistentFunction - input.hack:10:5 - Function f3 is not defined \ No newline at end of file