diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index 4c13f4a3cb..001d0316a5 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -656,6 +656,12 @@ bool TypeSystem::try_lookup_method(const std::string& type_name, MethodInfo* info) const { auto kv = m_types.find(type_name); if (kv == m_types.end()) { + // try to look up a forward declared type. + auto fwd_dec_type = lookup_type_allow_partial_def(type_name); + if (tc(TypeSpec("basic"), TypeSpec(fwd_dec_type->get_name()))) { + // only allow this for basics. It technically should be safe for structures as well. + return try_lookup_method(fwd_dec_type, method_name, info); + } return false; } @@ -1834,5 +1840,22 @@ bool TypeSystem::should_use_virtual_methods(const Type* type, int method_id) con } bool TypeSystem::should_use_virtual_methods(const TypeSpec& type, int method_id) const { - return should_use_virtual_methods(lookup_type(type), method_id); + auto it = m_types.find(type.base_type()); + if (it != m_types.end()) { + // it's a fully defined type + return should_use_virtual_methods(it->second.get(), method_id); + } else { + // it's a partially defined type. + // for now, we will prohibit calling a method on something that's defined only as a structure + // because we don't know if it's actually a basic, and should use virtual methods. + auto fwd_dec_type = lookup_type_allow_partial_def(type); + if (fwd_dec_type->get_name() == "structure") { + throw_typesystem_error( + "Type {} was forward declared as structure and it is not safe to call a method.", + type.print()); + return false; + } else { + return should_use_virtual_methods(fwd_dec_type, method_id); + } + } } diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 714578a241..b70f8d89ed 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -3924,9 +3924,18 @@ FormElement* ConditionElement::make_not_equal_check_generic( pool.alloc_single_element_form( nullptr, GenericOperator::make_fixed(FixedOperatorKind::NULLP), source_forms.at(0))); } else { - return pool.alloc_element( - GenericOperator::make_fixed(FixedOperatorKind::NEQ), - cast_to_64_bit(source_forms, source_types, pool, env)); + auto nice_constant = + try_make_constant_for_compare(source_forms.at(1), source_types.at(0), pool, env); + if (nice_constant) { + auto forms_with_cast = source_forms; + forms_with_cast.at(1) = nice_constant; + return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::NEQ), + forms_with_cast); + } else { + return pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::NEQ), + cast_to_64_bit(source_forms, source_types, pool, env)); + } } } diff --git a/docs/markdown/progress-notes/changelog.md b/docs/markdown/progress-notes/changelog.md index 0381b4e828..2cf5e1739e 100644 --- a/docs/markdown/progress-notes/changelog.md +++ b/docs/markdown/progress-notes/changelog.md @@ -200,4 +200,6 @@ - Converting a float larger than `INT32_MAX` now saturates to INT32_MAX, like on a real PS2. - Treating a float as a 64-bit integer now sign extends, like on a real PS2 - It is now an error to have two arguments with the same name. -- It is now a warning to redefine a constant. \ No newline at end of file +- It is now a warning to redefine a constant. +- Fix a bug where the size of static boxed arrays was only `length` and not `allocated-length` +- It is now possible to call a method on a forward declared type. The forward declared type must be a basic. \ No newline at end of file diff --git a/goal_src/engine/game/projectiles.gc b/goal_src/engine/game/projectiles.gc index 5d93fd1cc3..d5c8903186 100644 --- a/goal_src/engine/game/projectiles.gc +++ b/goal_src/engine/game/projectiles.gc @@ -307,7 +307,7 @@ (when (and (not sv-224) (>= (-> arg0 coverage) 0.9)) (set! sv-80 (logior sv-80 2)) (set! (-> arg0 ground-poly-normal quad) (-> arg0 poly-normal quad)) - (when (!= (-> arg0 poly-pat mode) 1) + (when (!= (-> arg0 poly-pat mode) (pat-mode wall)) (set! (-> arg0 ground-pat) (-> arg0 poly-pat)) (set! (-> arg0 ground-touch-point quad) (-> arg1 best-tri intersect quad)) ) diff --git a/goal_src/levels/village3/miners.gc b/goal_src/levels/village3/miners.gc index 7c5a0c39c0..d2a54cdbc9 100644 --- a/goal_src/levels/village3/miners.gc +++ b/goal_src/levels/village3/miners.gc @@ -5,29 +5,7 @@ ;; name in dgo: miners ;; dgos: L1, VI3 -(define-extern *cavegem-sg* skeleton-group) -(define-extern *minershort-sg* skeleton-group) -(define-extern *minertall-sg* skeleton-group) - -;; definition of type minertall -(deftype minertall (process-taskable) - () - :heap-base #x110 - :method-count-assert 53 - :size-assert #x17c - :flag-assert #x350110017c - ) - -;; I reordered this! -;; definition of type minershort -(deftype minershort (process-taskable) - ((other-miner minertall :offset-assert 380) - ) - :heap-base #x110 - :method-count-assert 53 - :size-assert #x180 - :flag-assert #x3501100180 - ) +(declare-type minershort process-taskable) ;; definition for function miners-anim-loop (defbehavior miners-anim-loop minershort () @@ -59,6 +37,30 @@ (none) ) +(define-extern *cavegem-sg* skeleton-group) +(define-extern *minershort-sg* skeleton-group) +(define-extern *minertall-sg* skeleton-group) + +;; definition of type minertall +(deftype minertall (process-taskable) + () + :heap-base #x110 + :method-count-assert 53 + :size-assert #x17c + :flag-assert #x350110017c + ) + +;; I reordered this! +;; definition of type minershort +(deftype minershort (process-taskable) + ((other-miner minertall :offset-assert 380) + ) + :heap-base #x110 + :method-count-assert 53 + :size-assert #x180 + :flag-assert #x3501100180 + ) + ;; failed to figure out what this is: (let ((v1-2 @@ -890,7 +892,7 @@ ) ) ((= v1-59 1) - (if (!= (get-task-status (game-task cave-gnawers)) 5) + (if (!= (get-task-status (game-task cave-gnawers)) (task-status need-reminder)) (set! s4-2 2) ) ) @@ -920,7 +922,7 @@ ) ) (else - (if (!= (get-task-status (game-task snow-eggtop)) 5) + (if (!= (get-task-status (game-task snow-eggtop)) (task-status need-reminder)) (set! s4-2 0) ) ) diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index 13af6c3a37..fc84796bd7 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -901,7 +901,7 @@ StaticResult Compiler::fill_static_boxed_array(const goos::Object& form, auto deref_info = m_ts.get_deref_info(pointer_type); assert(deref_info.can_deref); assert(deref_info.mem_deref); - auto array_data_size_bytes = length * deref_info.stride; + auto array_data_size_bytes = allocated_length * deref_info.stride; // todo, segments std::unique_ptr obj; obj = std::make_unique(MAIN_SEGMENT, "array"); diff --git a/test/decompiler/reference/engine/game/projectiles_REF.gc b/test/decompiler/reference/engine/game/projectiles_REF.gc index dd2cbad731..7087e41630 100644 --- a/test/decompiler/reference/engine/game/projectiles_REF.gc +++ b/test/decompiler/reference/engine/game/projectiles_REF.gc @@ -320,7 +320,7 @@ (when (and (not sv-224) (>= (-> arg0 coverage) 0.9)) (set! sv-80 (logior sv-80 2)) (set! (-> arg0 ground-poly-normal quad) (-> arg0 poly-normal quad)) - (when (!= (-> arg0 poly-pat mode) 1) + (when (!= (-> arg0 poly-pat mode) (pat-mode wall)) (set! (-> arg0 ground-pat) (-> arg0 poly-pat)) (set! (-> arg0 ground-touch-point quad) (-> arg1 best-tri intersect quad)) ) diff --git a/test/decompiler/reference/levels/common/plat_REF.gc b/test/decompiler/reference/levels/common/plat_REF.gc index 50b7280b96..51b5e2d6e9 100644 --- a/test/decompiler/reference/levels/common/plat_REF.gc +++ b/test/decompiler/reference/levels/common/plat_REF.gc @@ -36,74 +36,78 @@ (new 'static 'sp-field-init-spec :field #x6 :flags #x1 - :initial-value #x3fc00000 - :random-mult #x3f800000 + :initial-valuef 1.5 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #xb :flags #x1 - :initial-value #x45800000 - :random-mult #x3f800000 + :initial-valuef 4096.0 + :random-multf 1.0 + ) + (new 'static 'sp-field-init-spec + :field #xe + :initial-valuef (the-as float #x5) + :random-multf (the-as float #x1) ) - (new 'static 'sp-field-init-spec :field #xe :initial-value 5 :random-mult 1) (new 'static 'sp-field-init-spec :field #x12 :flags #x1 - :initial-value #x45a66666 - :random-mult #x3f800000 + :initial-valuef 5324.8 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x13 :flags #x1 - :initial-value #x45800000 - :random-mult #x3f800000 + :initial-valuef 4096.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x14 :flags #x1 - :initial-value #x45666666 - :random-mult #x3f800000 + :initial-valuef 3686.4 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x1a :flags #x1 - :initial-value #x415a740e - :random-mult #x3f800000 + :initial-valuef 13.653334 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x23 :flags #x1 - :initial-value -1048374674 - :random-mult #x3f800000 + :initial-valuef -16.383999 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x2e - :initial-value 25 - :random-mult 1 + :initial-valuef (the-as float #x19) + :random-multf (the-as float #x1) ) (new 'static 'sp-field-init-spec :field #x2f - :initial-value #x100 - :random-mult 1 + :initial-valuef (the-as float #x100) + :random-multf (the-as float #x1) ) (new 'static 'sp-field-init-spec :field #x3a :flags #x1 - :initial-value #x46c71c72 - :random-range #x45e38e39 - :random-mult #x3f800000 + :initial-valuef 25486.223 + :random-rangef 7281.778 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x3b :flags #x1 - :random-range #x47800000 - :random-mult #x3f800000 + :random-rangef 65536.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x3e :flags #x1 - :initial-value #x46400000 - :random-mult #x3f800000 + :initial-valuef 12288.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x43) ) @@ -116,110 +120,113 @@ (new 'static 'sparticle-launcher :init-specs (new 'static 'inline-array sp-field-init-spec 19 - (new 'static 'sp-field-init-spec :field #x1 :initial-value #x200f00) + (new 'static 'sp-field-init-spec + :field #x1 + :initial-valuef (the-as float #x200f00) + ) (new 'static 'sp-field-init-spec :field #x6 :flags #x1 - :initial-value #x40000000 - :random-mult #x3f800000 + :initial-valuef 2.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #xb :flags #x1 - :initial-value #x45c00000 - :random-mult #x3f800000 + :initial-valuef 6144.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #xd :flags #x1 - :initial-value #x46000000 - :random-range #x45800000 - :random-mult #x3f800000 + :initial-valuef 8192.0 + :random-rangef 4096.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x11 :flags #x3 - :initial-value -4 - :random-mult 1 + :initial-valuef (the-as float #xfffffffc) + :random-multf (the-as float #x1) ) (new 'static 'sp-field-init-spec :field #x13 :flags #x1 - :random-range #x42800000 - :random-mult #x3f800000 + :random-rangef 64.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x14 :flags #x1 - :initial-value #x43000000 - :random-range #x43000000 - :random-mult #x3f800000 + :initial-valuef 128.0 + :random-rangef 128.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x15 :flags #x1 - :initial-value #x41800000 - :random-range #x42000000 - :random-mult #x3f800000 + :initial-valuef 16.0 + :random-rangef 32.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x1a :flags #x1 - :initial-value #x4223d70a - :random-mult #x3f800000 + :initial-valuef 40.96 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x22 :flags #x1 - :initial-value -1092979698 - :random-mult #x3f800000 + :initial-valuef -0.42666668 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x24 :flags #x1 - :initial-value -1096558838 - :random-mult #x3f800000 + :initial-valuef -0.32 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x26 :flags #x1 - :initial-value -1106522267 - :random-mult #x3f800000 + :initial-valuef -0.13653333 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x2d :flags #x1 - :initial-value #x3f75c28f - :random-mult #x3f800000 + :initial-valuef 0.96 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x2e - :initial-value #x96 - :random-mult 1 + :initial-valuef (the-as float #x96) + :random-multf (the-as float #x1) ) (new 'static 'sp-field-init-spec :field #x2f - :initial-value 12 - :random-mult 1 + :initial-valuef (the-as float #xc) + :random-multf (the-as float #x1) ) (new 'static 'sp-field-init-spec :field #x3a :flags #x1 - :initial-value #x46b8e38e - :random-range #x468e38e4 - :random-mult #x3f800000 + :initial-valuef 23665.777 + :random-rangef 18204.445 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x3b :flags #x1 - :random-range #x47800000 - :random-mult #x3f800000 + :random-rangef 65536.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x3e :flags #x1 - :initial-value #x46400000 - :random-mult #x3f800000 + :initial-valuef 12288.0 + :random-multf 1.0 ) (new 'static 'sp-field-init-spec :field #x43) ) diff --git a/test/decompiler/reference/levels/village3/miners_REF.gc b/test/decompiler/reference/levels/village3/miners_REF.gc index 3bf533ef50..a19f9b5a48 100644 --- a/test/decompiler/reference/levels/village3/miners_REF.gc +++ b/test/decompiler/reference/levels/village3/miners_REF.gc @@ -903,7 +903,11 @@ ) ) ((= v1-59 1) - (if (!= (get-task-status (game-task cave-gnawers)) 5) + (if + (!= + (get-task-status (game-task cave-gnawers)) + (task-status need-reminder) + ) (set! s4-2 2) ) ) @@ -933,7 +937,11 @@ ) ) (else - (if (!= (get-task-status (game-task snow-eggtop)) 5) + (if + (!= + (get-task-status (game-task snow-eggtop)) + (task-status need-reminder) + ) (set! s4-2 0) ) ) diff --git a/test/goalc/source_templates/with_game/test-forward-declared-method.gc b/test/goalc/source_templates/with_game/test-forward-declared-method.gc new file mode 100644 index 0000000000..55c153957d --- /dev/null +++ b/test/goalc/source_templates/with_game/test-forward-declared-method.gc @@ -0,0 +1,35 @@ + + +(deftype test-parent-type (basic) + () + (:methods + (test-method (_type_) int) + ) + ) + +(defmethod test-method test-parent-type ((obj test-parent-type)) + 4 + ) + +(declare-type test-child-type test-parent-type) + + +(defun test-method-call ((obj test-child-type)) + (test-method obj) + ) + + + +(deftype test-child-type (test-parent-type) + () + ) + +(defmethod test-method test-child-type ((obj test-child-type)) + 12 + ) + + +(format #t "~d ~d~%" + (test-method (new 'static 'test-parent-type)) + (test-method-call (new 'static 'test-child-type)) + ) \ No newline at end of file diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index e5d66437ab..d0c0a80b4b 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -890,6 +890,11 @@ TEST_F(WithGameTests, ProcessAllocation) { {"diff is 16\n0\n"}); } +TEST_F(WithGameTests, MethodCallForwardDeclared) { + shared_compiler->runner.run_static_test(env, testCategory, "test-forward-declared-method.gc", + {"4 12\n0\n"}); +} + TEST(TypeConsistency, TypeConsistency) { Compiler compiler; compiler.enable_throw_on_redefines(); diff --git a/third-party/googletest b/third-party/googletest index 7153098229..955c7f837e 160000 --- a/third-party/googletest +++ b/third-party/googletest @@ -1 +1 @@ -Subproject commit 7153098229e88295f9655ff1d3b0e2fa9eada5f8 +Subproject commit 955c7f837efad184ec63e771c42542d37545eaef